{
  "openapi": "3.1.0",
  "info": {
    "title": "Natter API v1",
    "version": "1.0.0",
    "summary": "Current app-facing and provider /v1 routes served by natter-api.",
    "description": "Every /v1 route currently mounted by natter-api on api.natterapp.com. The unused Matrix Business API and its appservice callbacks were removed (D337). The separately documented Go Business text API uses its own Live and Test keys. No Business key enables the retired routes. Shared app routes retain their existing Matrix access-token requirements; ordinary registration start routes take no bearer, incoming status/cancel require an app-private polling capability, and provider callbacks require their signed payloads. Errors use the ApiError envelope. The retained webhooks section records historical kind/envelope vocabulary only; it is not an active callback service or the hosted preview contract. See business-hosted.v1.json for the separately labelled hosted text API, and docs/STATUS.md for commissioning.",
    "contact": {
      "name": "Masons Mail",
      "url": "https://natterapp.com"
    }
  },
  "servers": [
    {
      "url": "https://api.natterapp.com"
    }
  ],
  "tags": [
    {
      "name": "registration",
      "description": "Phone registration for the app (SPEC §5)."
    },
    {
      "name": "app",
      "description": "Routes the phone app calls with its Matrix access token."
    }
  ],
  "components": {
    "securitySchemes": {
      "developmentGrant": {
        "type": "http",
        "scheme": "bearer",
        "description": "Administrator-issued, installation-bound, single-use development enrollment grant. Never a master or fixed token."
      },
      "matrixToken": {
        "type": "http",
        "scheme": "bearer",
        "description": "A Natter user's Matrix access token, checked with Synapse's whoami."
      },
      "whatsappWebhookSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Hub-Signature-256",
        "description": "sha256=<64 lowercase hex>: HMAC-SHA256 of the exact raw request bytes using the dedicated Meta app secret. No shared user or business bearer token is accepted."
      },
      "telnyxWebhookSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "telnyx-signature-ed25519",
        "description": "Canonical base64 Ed25519 signature over ASCII telnyx-timestamp, |, then the exact raw request bytes, verified with the configured Telnyx public key. Timestamp must be within five minutes of server time."
      }
    },
    "responses": {
      "OwnAccount": {
        "description": "Private account details for the freshly authenticated caller only. Never a peer profile or a phone visibility policy.",
        "headers": {
          "Cache-Control": {
            "schema": {
              "type": "string",
              "const": "private, no-store"
            }
          },
          "Vary": {
            "schema": {
              "type": "string",
              "const": "Authorization"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/OwnAccount"
            }
          }
        }
      },
      "AccountUnavailable": {
        "description": "The private account service or its authoritative state is unavailable (account_unavailable). No sensitive diagnostics are returned.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "BadRequest": {
        "description": "The body or a parameter failed validation, or a cross-field rule (`invalid_request`); a webhook URL was refused (`webhook_invalid`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "No or invalid Matrix access token (`unauthorized`), or a suspended user (`user_suspended`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      },
      "RateLimited": {
        "description": "Over the tier's send rate or a per-user cap; `retry_after_s` says when to retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            }
          }
        }
      }
    },
    "schemas": {
      "RelaySignupContextResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["attached_passkey", "detached_passkey", "existing_account"],
        "properties": {
          "attached_passkey": {
            "type": "boolean",
            "description": "The number's attached, live account has at least one passkey: offer the restore first. Not a refusal."
          },
          "detached_passkey": {
            "type": "boolean",
            "description": "A live account Start fresh detached from this number less than 30 days ago has at least one passkey (N9)."
          },
          "existing_account": {
            "type": "boolean"
          }
        }
      },
      "RegistrationTimingRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["attempt_id", "timing"],
        "properties": {
          "attempt_id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^[0-9]{6}$"
          },
          "completion_grant": {
            "type": "string"
          },
          "timing": {
            "type": "object",
            "additionalProperties": false,
            "required": ["platform", "proof_received_ms", "login_ms"],
            "properties": {
              "platform": {
                "type": "string",
                "enum": ["android", "ios", "other"]
              },
              "composer_opened_ms": {
                "type": "integer",
                "minimum": 0,
                "maximum": 600000
              },
              "composer_sent_ms": {
                "type": "integer",
                "minimum": 0,
                "maximum": 600000
              },
              "proof_received_ms": {
                "type": "integer",
                "minimum": 0,
                "maximum": 600000
              },
              "login_ms": {
                "type": "integer",
                "minimum": 0,
                "maximum": 600000
              }
            }
          }
        },
        "oneOf": [
          {
            "required": ["code"]
          },
          {
            "required": ["completion_grant"]
          }
        ]
      },
      "CanonicalUsername": {
        "type": "string",
        "pattern": "^[a-z][a-z0-9_]{2,29}$",
        "description": "Chosen, unique public handle without @. Input is trimmed, removes one leading @, and lowercased. Reserved names cannot be claimed. Previous handles remain reserved to their original owner and are not lookup aliases."
      },
      "OwnAccount": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "matrix_user_id",
          "phone_e164",
          "phone_verified",
          "username",
          "phone_discoverable",
          "profile_setup_complete"
        ],
        "properties": {
          "matrix_user_id": {
            "$ref": "#/components/schemas/MatrixUserId"
          },
          "phone_e164": {
            "$ref": "#/components/schemas/E164"
          },
          "phone_verified": {
            "type": "boolean",
            "const": true
          },
          "username": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CanonicalUsername"
              },
              {
                "type": "null"
              }
            ]
          },
          "phone_discoverable": {
            "type": "boolean",
            "description": "Whether future exact phone/hash discovery can return this account. Does not publish the number or remove existing chats/cached matches."
          },
          "profile_setup_complete": {
            "type": "boolean",
            "description": "An idempotent onboarding preference, not an independent proof of account ownership."
          }
        }
      },
      "UsernameChangeRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["username", "expected_username"],
        "properties": {
          "username": {
            "type": ["string", "null"],
            "maxLength": 64,
            "description": "Chosen handle, or null to clear the active handle. Clearing never releases its reservation to another account."
          },
          "expected_username": {
            "type": ["string", "null"],
            "maxLength": 64,
            "description": "Current handle last read from /v1/me; stale changes fail without overwriting a concurrent edit."
          }
        }
      },
      "UsernameLookupResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["match"],
        "properties": {
          "match": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "additionalProperties": false,
                "required": ["matrix_user_id", "username"],
                "properties": {
                  "matrix_user_id": {
                    "$ref": "#/components/schemas/MatrixUserId"
                  },
                  "username": {
                    "$ref": "#/components/schemas/CanonicalUsername"
                  }
                }
              }
            ]
          }
        }
      },
      "ApiError": {
        "type": "object",
        "required": ["error", "message"],
        "additionalProperties": false,
        "properties": {
          "error": {
            "type": "string",
            "description": "Machine-readable code; the list is `API_ERROR_CODES` in packages/contracts and the test pins it.",
            "enum": [
              "invalid_request",
              "invalid_phone",
              "prefix_blocked",
              "rate_limited",
              "attestation_required",
              "sms_provider_failed",
              "channel_unavailable",
              "delivery_provider_failed",
              "attempt_not_found",
              "attempt_expired",
              "attempt_burned",
              "attempt_consumed",
              "code_mismatch",
              "verification_pending",
              "unauthorized",
              "synapse_unavailable",
              "user_suspended",
              "link_code_invalid",
              "link_unavailable",
              "masonsmail_unavailable",
              "sms_not_configured",
              "invalid_api_key",
              "business_suspended",
              "business_paused",
              "no_relationship",
              "user_opted_out",
              "number_not_verified",
              "business_number_not_allowed",
              "number_not_found",
              "number_details_unavailable",
              "number_in_use",
              "media_not_found",
              "media_too_large",
              "unsupported_media_type",
              "conversation_not_found",
              "webhook_invalid",
              "idempotency_conflict",
              "internal",
              "account_unavailable",
              "username_invalid",
              "username_unavailable",
              "username_changed",
              "username_limit_reached",
              "legacy_registration_retired",
              "number_suspended",
              "too_many_accounts",
              "account_exists",
              "timing_unavailable",
              "not_found",
              "conflict",
              "attestation_invalid",
              "attestation_unavailable",
              "unavailable"
            ]
          },
          "message": {
            "type": "string",
            "description": "Human-readable; never carries a phone number, a Matrix id, a room id, a message body or a secret."
          },
          "retry_after_s": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "E164": {
        "type": "string",
        "pattern": "^\\+[1-9]\\d{6,14}$",
        "description": "Canonical E.164, e.g. `+46701234567`."
      },
      "MatrixUserId": {
        "type": "string",
        "pattern": "^@[a-z0-9._=/+-]+:[a-z0-9.-]+$",
        "maxLength": 255
      },
      "Uuid": {
        "type": "string",
        "format": "uuid"
      },
      "DateTime": {
        "type": "string",
        "format": "date-time"
      },
      "RegistrationCapabilities": {
        "type": "object",
        "required": ["version", "channels", "preferred_channel"],
        "additionalProperties": false,
        "properties": {
          "version": {
            "type": "integer",
            "const": 1
          },
          "channels": {
            "type": "object",
            "required": ["sms", "whatsapp"],
            "additionalProperties": false,
            "properties": {
              "sms": {
                "type": "boolean"
              },
              "whatsapp": {
                "type": "boolean"
              }
            }
          },
          "preferred_channel": {
            "enum": ["whatsapp", "sms", null]
          }
        }
      },
      "RegisterStartRequest": {
        "type": "object",
        "required": ["phone_e164", "device_name", "app_build"],
        "additionalProperties": false,
        "properties": {
          "phone_e164": {
            "$ref": "#/components/schemas/E164"
          },
          "device_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "app_build": {
            "type": "integer",
            "minimum": 1
          },
          "channel": {
            "type": "string",
            "enum": ["sms", "whatsapp"],
            "description": "Explicit delivery choice. Omission preserves legacy SMS; no automatic provider fallback."
          },
          "attestation": {
            "type": "object",
            "required": ["platform", "token"],
            "additionalProperties": false,
            "properties": {
              "platform": {
                "type": "string",
                "enum": ["android", "ios"]
              },
              "token": {
                "type": "string",
                "minLength": 1,
                "maxLength": 16384
              }
            }
          }
        }
      },
      "RegisterStartResponse": {
        "type": "object",
        "required": ["attempt_id", "resend_after_s"],
        "additionalProperties": false,
        "properties": {
          "attempt_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "resend_after_s": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "RegisterVerifyRequest": {
        "type": "object",
        "required": ["attempt_id", "code"],
        "additionalProperties": false,
        "properties": {
          "attempt_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^\\d{6}$"
          },
          "keep_existing_devices": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "RegisterVerifyResponse": {
        "type": "object",
        "required": ["matrix_user_id", "access_token", "device_id", "homeserver"],
        "additionalProperties": false,
        "properties": {
          "matrix_user_id": {
            "$ref": "#/components/schemas/MatrixUserId"
          },
          "access_token": {
            "type": "string",
            "minLength": 1
          },
          "device_id": {
            "type": "string",
            "minLength": 1
          },
          "homeserver": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "RelayFreshRequest": {
        "type": "object",
        "required": [
          "attempt_id",
          "transition_id",
          "account",
          "device",
          "access_token",
          "certificate"
        ],
        "additionalProperties": false,
        "properties": {
          "attempt_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "transition_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "account": {
            "type": "string",
            "pattern": "^rcon_[0-9a-f]{32}$"
          },
          "device": {
            "type": "string",
            "pattern": "^rdev_[0-9a-f]{32}$"
          },
          "access_token": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "Client-generated 256-bit bearer, persisted locally before this request. Never returned or logged by the server."
          },
          "code": {
            "type": "string",
            "pattern": "^\\d{6}$",
            "description": "Six-digit code from an outgoing SMS or WhatsApp attempt. Mutually exclusive with completion_grant."
          },
          "certificate": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "version",
              "purpose",
              "device",
              "ed25519",
              "curve25519",
              "signature"
            ],
            "properties": {
              "version": {
                "type": "integer",
                "const": 1
              },
              "purpose": {
                "type": "string",
                "const": "natter.device-keys"
              },
              "device": {
                "type": "object",
                "additionalProperties": false,
                "required": ["account", "device"],
                "properties": {
                  "account": {
                    "type": "string",
                    "pattern": "^rcon_[0-9a-f]{32}$"
                  },
                  "device": {
                    "type": "string",
                    "pattern": "^rdev_[0-9a-f]{32}$"
                  }
                }
              },
              "ed25519": {
                "type": "string",
                "description": "Canonical base64 Ed25519 public key, 32 bytes."
              },
              "curve25519": {
                "type": "string",
                "description": "Canonical base64 Curve25519 public key, 32 bytes."
              },
              "signature": {
                "type": "string",
                "description": "Canonical base64 Ed25519 signature over the device-key statement, 64 bytes."
              }
            }
          },
          "completion_grant": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "Canonical base64url 32-byte private grant from verified incoming WhatsApp status. Mutually exclusive with code. The provider message challenge and poll token are never accepted here."
          },
          "new_account_only": {
            "type": "boolean",
            "const": true,
            "description": "Optional D245 guard for automatic first signup. Checked under the phone lock; an existing live account causes account_exists without consuming the proof or detaching an account. Included in the frozen retry intent."
          }
        },
        "oneOf": [
          {
            "required": ["code"],
            "not": {
              "required": ["completion_grant"]
            }
          },
          {
            "required": ["completion_grant"],
            "not": {
              "required": ["code"]
            }
          }
        ]
      },
      "RelayFreshResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["account", "device", "generation", "credential_active", "replayed"],
        "properties": {
          "account": {
            "type": "string",
            "pattern": "^rcon_[0-9a-f]{32}$"
          },
          "device": {
            "type": "string",
            "pattern": "^rdev_[0-9a-f]{32}$"
          },
          "generation": {
            "type": "string",
            "pattern": "^[1-9][0-9]*$"
          },
          "credential_active": {
            "type": "boolean",
            "description": "False if this exact retry names an incarnation retired or revoked after its first success."
          },
          "replayed": {
            "type": "boolean"
          }
        }
      },
      "RelayNumberProofRequest": {
        "type": "object",
        "required": ["attempt_id", "proof_hash"],
        "additionalProperties": false,
        "properties": {
          "attempt_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^\\d{6}$",
            "description": "Six-digit code from an outgoing SMS or WhatsApp attempt. Mutually exclusive with completion_grant."
          },
          "proof_hash": {
            "type": "string",
            "pattern": "^[A-Za-z0-9+/]{43}=$",
            "description": "Standard base64 of the SHA-256 of the UTF-8 bytes of the phone-held secret (32 random bytes as 43-character unpadded base64url). The secret itself goes only to the relay restore routes."
          },
          "completion_grant": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "Canonical base64url 32-byte private grant from verified incoming WhatsApp status. Mutually exclusive with code. The provider message challenge and poll token are never accepted here."
          }
        },
        "oneOf": [
          {
            "required": ["code"],
            "not": {
              "required": ["completion_grant"]
            }
          },
          {
            "required": ["completion_grant"],
            "not": {
              "required": ["code"]
            }
          }
        ]
      },
      "RelayPasskeyAccountsRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["attempt_id"],
        "properties": {
          "attempt_id": {
            "type": "string",
            "format": "uuid"
          },
          "code": {
            "type": "string",
            "pattern": "^\\d{6}$",
            "description": "Six-digit code from an outgoing SMS or WhatsApp attempt. Mutually exclusive with completion_grant."
          },
          "completion_grant": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "Canonical base64url 32-byte private grant from verified incoming WhatsApp status. Mutually exclusive with code. The provider message challenge and poll token are never accepted here."
          }
        },
        "oneOf": [
          {
            "required": ["code"],
            "not": {
              "required": ["completion_grant"]
            }
          },
          {
            "required": ["completion_grant"],
            "not": {
              "required": ["code"]
            }
          }
        ]
      },
      "RelayPasskeyAccountsResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["attached_passkey", "detached_passkey"],
        "properties": {
          "attached_passkey": {
            "type": "boolean",
            "description": "The number's attached, live account has at least one passkey: offer the restore first. Not a refusal."
          },
          "detached_passkey": {
            "type": "boolean",
            "description": "A live account Start fresh detached from this number less than 30 days ago has at least one passkey (N9)."
          }
        }
      },
      "RelayNumberProofResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": ["expires_at", "replayed"],
        "properties": {
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "The relay refuses the proof from this instant (ten minutes after redemption)."
          },
          "replayed": {
            "type": "boolean"
          }
        }
      },
      "HashDetailsResponse": {
        "type": "object",
        "required": ["algorithm", "pepper", "lookup_max"],
        "additionalProperties": false,
        "properties": {
          "algorithm": {
            "type": "string",
            "const": "sha256"
          },
          "pepper": {
            "type": "string",
            "minLength": 32
          },
          "lookup_max": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "ContactsLookupRequest": {
        "type": "object",
        "required": ["hashes"],
        "additionalProperties": false,
        "properties": {
          "hashes": {
            "type": "array",
            "minItems": 1,
            "maxItems": 5000,
            "items": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            }
          }
        }
      },
      "ContactsLookupResponse": {
        "type": "object",
        "required": ["matches"],
        "additionalProperties": false,
        "properties": {
          "matches": {
            "type": "array",
            "items": {
              "type": "object",
              "required": ["hash", "matrix_user_id", "kind"],
              "additionalProperties": false,
              "properties": {
                "hash": {
                  "type": "string",
                  "pattern": "^[0-9a-f]{64}$"
                },
                "matrix_user_id": {
                  "type": "string",
                  "minLength": 1
                },
                "kind": {
                  "type": "string",
                  "enum": ["user"],
                  "description": "Current contact discovery returns ordinary user matches only. Business number discovery and the former Matrix Business conversation-opening route are unavailable."
                }
              }
            }
          }
        }
      },
      "LinkConfirmRequest": {
        "type": "object",
        "required": ["code"],
        "additionalProperties": false,
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^\\d{6}$"
          }
        }
      },
      "LinkInviteRequest": {
        "type": "object",
        "required": ["email"],
        "additionalProperties": false,
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "maxLength": 254
          }
        }
      },
      "WebhookKind": {
        "type": "string",
        "enum": ["message", "status", "opt_out", "opt_in", "policy"]
      },
      "WebhookEnvelope": {
        "type": "object",
        "required": ["id", "kind", "created_at", "business_id", "data"],
        "additionalProperties": false,
        "description": "The JSON body of every webhook delivery. `id` doubles as `X-Natter-Event-Id` and is stable across retries.",
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "kind": {
            "$ref": "#/components/schemas/WebhookKind"
          },
          "created_at": {
            "$ref": "#/components/schemas/DateTime"
          },
          "business_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "data": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "RegistrationMethods": {
        "type": "object",
        "additionalProperties": false,
        "required": ["version", "methods", "preferred_method"],
        "properties": {
          "version": {
            "type": "integer",
            "const": 2
          },
          "methods": {
            "type": "array",
            "maxItems": 4,
            "description": "Enabled, ready methods in operator preference order. SMS receipt is omitted unless an outgoing proof method is also ready. Country eligibility is enforced again when an attempt starts.",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": ["id", "countries"],
              "properties": {
                "id": {
                  "type": "string",
                  "enum": ["whatsapp_receive", "sms_receive", "whatsapp_send", "sms_send"]
                },
                "countries": {
                  "type": "array",
                  "maxItems": 250,
                  "uniqueItems": true,
                  "description": "Uppercase country codes. An empty list permits all countries admitted by the method and provider; it does not establish international SMS reachability.",
                  "items": {
                    "type": "string",
                    "pattern": "^[A-Z]{2}$"
                  }
                }
              }
            }
          },
          "preferred_method": {
            "type": ["string", "null"],
            "enum": ["whatsapp_receive", "sms_receive", "whatsapp_send", "sms_send", null],
            "description": "First available method, or null when none is available."
          }
        }
      },
      "InboundRegistrationStartRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["phone_e164", "device_name", "app_build", "method"],
        "properties": {
          "phone_e164": {
            "$ref": "#/components/schemas/E164"
          },
          "device_name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          },
          "app_build": {
            "type": "integer",
            "minimum": 1
          },
          "attestation": {
            "type": "object",
            "required": ["platform", "token"],
            "additionalProperties": false,
            "properties": {
              "platform": {
                "type": "string",
                "enum": ["android", "ios"]
              },
              "token": {
                "type": "string",
                "minLength": 1,
                "maxLength": 16384
              }
            }
          },
          "method": {
            "type": "string",
            "enum": ["whatsapp_receive", "sms_receive"]
          }
        }
      },
      "InboundRegistrationStartResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "version",
          "attempt_id",
          "poll_token",
          "expires_at",
          "method",
          "receiver_e164",
          "message",
          "resend_after_s"
        ],
        "properties": {
          "version": {
            "type": "integer",
            "const": 1
          },
          "attempt_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "poll_token": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "Private app-session capability. Never put it in the outgoing message, a URL, analytics or logs."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Five minutes after creation."
          },
          "method": {
            "type": "string",
            "enum": ["whatsapp_receive", "sms_receive"]
          },
          "receiver_e164": {
            "$ref": "#/components/schemas/E164"
          },
          "message": {
            "type": "string",
            "pattern": "^NATTER [A-Za-z0-9_-]{32}$",
            "description": "Exact text for the external WhatsApp or SMS composer. The person must press Send. This message challenge is not a completion grant."
          },
          "resend_after_s": {
            "type": "integer",
            "const": 60
          }
        }
      },
      "InboundRegistrationSessionRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": ["attempt_id", "poll_token"],
        "properties": {
          "attempt_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "poll_token": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "The private capability returned only to the app that created the attempt."
          }
        }
      },
      "InboundRegistrationStatus": {
        "oneOf": [
          {
            "type": "object",
            "additionalProperties": false,
            "required": ["state", "expires_at", "completion_grant"],
            "properties": {
              "state": {
                "type": "string",
                "const": "verified"
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              },
              "completion_grant": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{43}$",
                "description": "Private, one-use phone proof for the relay registration routes. Returned only after accepted WhatsApp phone identity matches the requested number; never sent to the provider."
              }
            }
          },
          {
            "type": "object",
            "additionalProperties": false,
            "required": ["state", "expires_at"],
            "properties": {
              "state": {
                "type": "string",
                "enum": [
                  "pending",
                  "needs_stronger_verification",
                  "number_mismatch",
                  "number_unavailable",
                  "cancelled",
                  "expired",
                  "unavailable"
                ],
                "description": "SMS receipt produces needs_stronger_verification and never a grant. Start an explicitly selected outgoing code attempt. number_unavailable includes a WhatsApp event without a usable phone identity; text or BSUID is not accepted as number proof."
              },
              "expires_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        ]
      },
      "ProviderWebhookAcknowledgement": {
        "type": "object",
        "additionalProperties": false,
        "required": ["received"],
        "properties": {
          "received": {
            "type": "boolean",
            "const": true
          }
        }
      },
      "WhatsAppIncomingWebhook": {
        "type": "object",
        "required": ["object", "entry"],
        "properties": {
          "object": {
            "type": "string",
            "const": "whatsapp_business_account"
          },
          "entry": {
            "type": "array",
            "maxItems": 8,
            "items": {
              "type": "object",
              "required": ["id", "changes"],
              "properties": {
                "id": {
                  "type": "string",
                  "maxLength": 64
                },
                "changes": {
                  "type": "array",
                  "maxItems": 20,
                  "items": {
                    "type": "object",
                    "required": ["field", "value"],
                    "properties": {
                      "field": {
                        "type": "string",
                        "maxLength": 64
                      },
                      "value": {
                        "type": "object",
                        "required": ["metadata"],
                        "properties": {
                          "messaging_product": {
                            "type": "string",
                            "const": "whatsapp"
                          },
                          "metadata": {
                            "type": "object",
                            "required": ["phone_number_id"],
                            "properties": {
                              "phone_number_id": {
                                "type": "string",
                                "maxLength": 64
                              }
                            }
                          },
                          "contacts": {
                            "type": "array",
                            "maxItems": 20,
                            "items": {
                              "type": "object",
                              "properties": {
                                "wa_id": {
                                  "type": "string",
                                  "maxLength": 128
                                }
                              }
                            }
                          },
                          "messages": {
                            "type": "array",
                            "maxItems": 20,
                            "items": {
                              "type": "object",
                              "required": ["id", "timestamp", "type"],
                              "properties": {
                                "id": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 256
                                },
                                "from": {
                                  "type": "string",
                                  "maxLength": 128
                                },
                                "timestamp": {
                                  "type": "string",
                                  "pattern": "^\\d{10}$"
                                },
                                "type": {
                                  "type": "string",
                                  "maxLength": 64
                                },
                                "text": {
                                  "type": "object",
                                  "required": ["body"],
                                  "properties": {
                                    "body": {
                                      "type": "string",
                                      "maxLength": 4096
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "TelnyxIncomingMessage": {
        "type": "object",
        "required": [
          "id",
          "direction",
          "type",
          "messaging_profile_id",
          "from",
          "to",
          "text"
        ],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "direction": {
            "type": "string",
            "const": "inbound"
          },
          "type": {
            "type": "string",
            "const": "SMS"
          },
          "messaging_profile_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "from": {
            "type": "object",
            "required": ["phone_number"],
            "properties": {
              "phone_number": {
                "$ref": "#/components/schemas/E164"
              }
            }
          },
          "to": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1,
            "items": {
              "type": "object",
              "required": ["phone_number"],
              "properties": {
                "phone_number": {
                  "$ref": "#/components/schemas/E164"
                }
              }
            }
          },
          "text": {
            "type": "string",
            "maxLength": 4096
          }
        }
      },
      "TelnyxFinalizedMessage": {
        "type": "object",
        "required": ["id", "messaging_profile_id", "direction", "type", "to"],
        "properties": {
          "id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "messaging_profile_id": {
            "$ref": "#/components/schemas/Uuid"
          },
          "direction": {
            "type": "string",
            "const": "outbound"
          },
          "type": {
            "type": "string",
            "const": "SMS"
          },
          "to": {
            "type": "array",
            "minItems": 1,
            "maxItems": 1,
            "items": {
              "type": "object",
              "required": ["status"],
              "properties": {
                "status": {
                  "type": "string",
                  "maxLength": 80
                }
              }
            }
          },
          "errors": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "type": "object",
              "required": ["code"],
              "properties": {
                "code": {
                  "type": "string",
                  "maxLength": 32
                }
              }
            }
          },
          "cost": {
            "description": "Optional provider cost. Only valid nonnegative decimal amounts and three-letter uppercase currency codes are recorded. An absent or invalid value is unknown, not zero."
          }
        }
      },
      "TelnyxIncomingWebhook": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["id", "event_type", "occurred_at", "payload"],
            "properties": {
              "id": {
                "$ref": "#/components/schemas/Uuid"
              },
              "event_type": {
                "type": "string",
                "maxLength": 64
              },
              "occurred_at": {
                "type": "string",
                "format": "date-time"
              },
              "payload": {}
            },
            "allOf": [
              {
                "if": {
                  "properties": {
                    "event_type": {
                      "const": "message.received"
                    }
                  }
                },
                "then": {
                  "properties": {
                    "payload": {
                      "$ref": "#/components/schemas/TelnyxIncomingMessage"
                    }
                  }
                }
              },
              {
                "if": {
                  "properties": {
                    "event_type": {
                      "const": "message.finalized"
                    }
                  }
                },
                "then": {
                  "properties": {
                    "payload": {
                      "$ref": "#/components/schemas/TelnyxFinalizedMessage"
                    }
                  }
                }
              }
            ]
          }
        }
      },
      "TelnyxDeliveryWebhook": {
        "type": "object",
        "required": ["data"],
        "properties": {
          "data": {
            "type": "object",
            "required": ["event_type", "payload"],
            "properties": {
              "event_type": {
                "type": "string",
                "maxLength": 80
              },
              "payload": {}
            },
            "allOf": [
              {
                "if": {
                  "properties": {
                    "event_type": {
                      "const": "message.finalized"
                    }
                  }
                },
                "then": {
                  "properties": {
                    "payload": {
                      "$ref": "#/components/schemas/TelnyxFinalizedMessage"
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  "paths": {
    "/v1/register/relay/signup-context": {
      "post": {
        "tags": ["registration"],
        "summary": "Get signup or recovery choices after proving the phone number",
        "description": "D245. The same non-consuming phone proof check as passkey-accounts. Adds existing_account for a live account currently or formerly associated with this number; never returns account identifiers. Only existing_account=false permits the guarded automatic new-account flow. Legacy clients continue using the unchanged two-boolean passkey-accounts route.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RelayPasskeyAccountsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The restorable accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelaySignupContextResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "`attempt_expired`, `attempt_burned`, `attempt_consumed` or `code_mismatch`."
          },
          "404": {
            "description": "Registration attempt does not exist."
          },
          "409": {
            "description": "verification_pending means the incoming proof has not completed and does not spend a wrong-code attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "channel_unavailable if the incoming method has since been disabled or is no longer ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/timing": {
      "post": {
        "tags": ["registration"],
        "summary": "Record best-effort signup durations after successful phone proof redemption",
        "description": "D245. Requires the matching consumed phone proof within ten minutes of consumption. First report wins; unavailable or failed telemetry never blocks login. Millisecond durations are client measurements from starting the chosen method. composer_sent_ms is accepted only for native iOS SMS completion, never inferred from WhatsApp launch. No extra phone, account, message body, code or grant is retained in the timing row. Existing attempt deletion cascades to this row.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegistrationTimingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Recorded, or an earlier report already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": ["recorded"],
                  "properties": {
                    "recorded": {
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "Proof mismatch or timing_unavailable (not consumed or outside the reporting window)."
          },
          "404": {
            "description": "Registration attempt does not exist."
          }
        }
      }
    },
    "/v1/me": {
      "get": {
        "tags": ["app"],
        "operationId": "ownAccount",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "summary": "Read the caller's private account details",
        "description": "Bypasses the ordinary authentication cache and freshly validates the token with Synapse. Default read cap120 per user per hour. Phone details are never returned for another user.",
        "responses": {
          "200": {
            "$ref": "#/components/responses/OwnAccount"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/AccountUnavailable"
          }
        }
      }
    },
    "/v1/me/username": {
      "put": {
        "tags": ["app"],
        "operationId": "changeOwnUsername",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "summary": "Claim, change or clear the caller's public username",
        "description": "Atomic expected-current edit. Prior names remain reserved permanently to the original owner, including tombstones after account deletion. Default5 attempts/user/hour and10 retained names/account. 1024-byte request limit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UsernameChangeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/OwnAccount"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "username_unavailable for a reserved/held name; username_changed for stale expected_username; username_limit_reached for the retained-name cap. Never reveals another owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Request body exceeds1024 bytes."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/AccountUnavailable"
          }
        }
      }
    },
    "/v1/me/discovery": {
      "put": {
        "tags": ["app"],
        "operationId": "changeOwnPhoneDiscovery",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "summary": "Set the caller's phone-discovery preference",
        "description": "Default on. False filters future phone/hash matches server-side; username lookup remains independent. This is not a phone-visibility audience. Default60 preference/setup writes/user/hour. 1024-byte body limit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["phone_discoverable"],
                "additionalProperties": false,
                "properties": {
                  "phone_discoverable": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/OwnAccount"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "description": "Request body exceeds1024 bytes."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/AccountUnavailable"
          }
        }
      }
    },
    "/v1/me/setup-complete": {
      "post": {
        "tags": ["app"],
        "operationId": "completeOwnProfileSetup",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "summary": "Idempotently mark first profile setup complete",
        "description": "Existing users are marked complete by migration; future accounts start incomplete. No other preference or username changes. Not a login or continuity gate. 1024-byte body limit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/OwnAccount"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "description": "Request body exceeds1024 bytes."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/AccountUnavailable"
          }
        }
      }
    },
    "/v1/contacts/lookup-username": {
      "post": {
        "tags": ["app"],
        "operationId": "lookupUsername",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "summary": "Match one exact chosen username",
        "description": "No prefix, fuzzy, bulk or directory enumeration route. Normalizes input like username claim. No phone fields. Suspended, unavailable, reserved, inactive previous handles, service and foreign identities return match:null. Shares phone lookup caps (default10 requests/user/hour,30/IP/hour). 1024-byte body limit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["username"],
                "additionalProperties": false,
                "properties": {
                  "username": {
                    "type": "string",
                    "maxLength": 64
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "An exact current username and ordinary local Matrix ID, or null.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsernameLookupResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "413": {
            "description": "Request body exceeds1024 bytes."
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/AccountUnavailable"
          }
        }
      }
    },
    "/v1/register/development": {
      "post": {
        "tags": ["registration"],
        "summary": "Redeem an administrator-issued development enrollment grant",
        "description": "Absent unless explicitly enabled in an HTTPS development deployment. Authorization is a short-lived single-use enrollment grant, bound to the phone and installation. Only separately provisioned development identities qualify; ordinary accounts cannot be adopted. This does not verify phone possession.",
        "security": [
          {
            "developmentGrant": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": ["phone_e164", "installation_id", "device_name", "app_build"],
                "properties": {
                  "phone_e164": {
                    "type": "string",
                    "pattern": "^\\+[1-9]\\d{6,14}$"
                  },
                  "installation_id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "device_name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  },
                  "app_build": {
                    "type": "integer",
                    "minimum": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ordinary Matrix access_token, matrix_user_id, device_id and homeserver, also authenticated by the Natter API."
          },
          "401": {
            "description": "Missing, expired, consumed, or mismatched enrollment grant."
          },
          "403": {
            "description": "Development enrollment disabled."
          },
          "404": {
            "description": "Route absent in the default production deployment."
          },
          "502": {
            "description": "Homeserver failed; grant remains consumed. Administrator must issue a new grant."
          }
        }
      }
    },
    "/v1/register/relay/fresh": {
      "post": {
        "tags": ["registration"],
        "summary": "Create a fresh relay incarnation with a verified one-use registration attempt",
        "description": "A fresh start, never restoration. The exact self-signed first-device certificate and a client-frozen 256-bit bearer are committed atomically with consuming the registration attempt. An exact retry returns the same receipt; a later-retired incarnation is reported inactive. No Matrix token, old device, room or backup is adopted. The exact request contains either a six-digit outgoing code or a private completion_grant, never both. Grants are issued only by verified incoming WhatsApp status and do not bypass passkey, trusted-device or fresh-start account rules. Incoming SMS receipt alone is not accepted.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RelayFreshRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Fresh incarnation committed or an exact retry answered; the bearer is never echoed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayFreshResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "registration proof failed, expired, burned or already consumed by another intent."
          },
          "404": {
            "description": "Registration attempt does not exist."
          },
          "409": {
            "description": "Transition or credential conflicts with an existing reservation. verification_pending means the incoming proof has not completed and does not spend a wrong-code attempt. account_exists refuses a guarded new-account request when another live account exists for this number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "channel_unavailable if the incoming method has since been disabled or is no longer ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/relay/passkey-accounts": {
      "post": {
        "tags": ["registration"],
        "summary": "Whether a passkey can restore an account of a verified number",
        "description": "D215. Verifies the phone proof like the relay redemptions (wrong tries counted and burning) but never consumes the attempt. Answers two booleans and never an account ID: `attached_passkey` when the attempt's number is attached to a live account with at least one passkey (the phone offers the passkey restore first; Start fresh stays allowed, owner ruling 2026-10-01), and `detached_passkey` when a live account that Start fresh detached from this number less than 30 days ago has one. The phone learns the account from the passkey assertion's user handle. A number without an account gets the same answer as one whose account has no passkey. The exact request contains either a six-digit outgoing code or a private completion_grant, never both. Grants are issued only by verified incoming WhatsApp status and do not bypass passkey, trusted-device or fresh-start account rules. Incoming SMS receipt alone is not accepted.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RelayPasskeyAccountsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The restorable accounts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayPasskeyAccountsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "`attempt_expired`, `attempt_burned`, `attempt_consumed` or `code_mismatch`."
          },
          "404": {
            "description": "Registration attempt does not exist."
          },
          "409": {
            "description": "verification_pending means the incoming proof has not completed and does not spend a wrong-code attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "channel_unavailable if the incoming method has since been disabled or is no longer ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/relay/number-proof": {
      "post": {
        "tags": ["registration"],
        "summary": "Redeem a verified one-use registration attempt into a single-use number proof",
        "description": "D192 passkey restore, first step. Proves possession of the attempt number and nothing else: the answer never depends on whether the number belongs to an account, and no account, device or phone value is returned. The phone keeps a random 256-bit secret and sends only its SHA-256; the relay consumes the proof once, within ten minutes, together with a passkey assertion for an account whose current number binding is this number. The attempt is consumed, so it can no longer start a fresh incarnation. An exact retry returns the same expiry. The exact request contains either a six-digit outgoing code or a private completion_grant, never both. Grants are issued only by verified incoming WhatsApp status and do not bypass passkey, trusted-device or fresh-start account rules. Incoming SMS receipt alone is not accepted.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RelayNumberProofRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Proof stored or an exact retry answered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RelayNumberProofResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "registration proof failed, expired, burned or already consumed by another intent."
          },
          "404": {
            "description": "Registration attempt does not exist."
          },
          "409": {
            "description": "The proof hash is already stored for another attempt. verification_pending means the incoming proof has not completed and does not spend a wrong-code attempt.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "channel_unavailable if the incoming method has since been disabled or is no longer ready.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/capabilities": {
      "get": {
        "tags": ["registration"],
        "summary": "Read deployment-wide registration delivery policy",
        "description": "No query parameters or identity lookup. Cache-Control: no-store. A supported channel does not imply every number is admitted: operator allow-listed test mode can advertise SMS without a real SMS sender. WhatsApp requires enabled, valid sealed provider configuration saved through Services. No provider request is made by this endpoint.",
        "security": [],
        "responses": {
          "200": {
            "description": "Versioned policy; both channels may be unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistrationCapabilities"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/register/methods": {
      "get": {
        "tags": ["registration"],
        "summary": "List ready verification methods in preference order",
        "description": "Accepts no query parameters and makes no provider request. Returns only enabled and ready methods. Saving credentials alone does not enable a method. Incoming WhatsApp also requires the operator record of external approval. Cache-Control: no-store.",
        "security": [],
        "responses": {
          "200": {
            "description": "Versioned methods and country rules; the list may be empty.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistrationMethods"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          }
        }
      }
    },
    "/v1/register/inbound/start": {
      "post": {
        "tags": ["registration"],
        "summary": "Prepare a user-sent verification message",
        "description": "Creates a five-minute incoming attempt without sending a provider message. The phone opens the external composer and the person sends the exact returned text. Enforces method/country readiness, a configured tested receiving route, attestation and registration abuse limits. Request body limit: 24,576 bytes. Cache-Control: no-store.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboundRegistrationStartRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "New attempt and private polling capability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboundRegistrationStartResponse"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request or invalid mobile phone number.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "403": {
            "description": "Country blocked or app attestation rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "channel_unavailable or attestation_unavailable; no usable method/route or attestation verifier unavailable.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/inbound/status": {
      "post": {
        "tags": ["registration"],
        "summary": "Read an incoming attempt using its private polling capability",
        "description": "Send the attempt and poll token in the body, never in a URL. Only verified incoming WhatsApp returns a completion grant. Incoming SMS requires an explicitly selected outgoing code and cannot prove a number by itself. Policy is checked again; disabled methods return unavailable. Request body limit: 1,024 bytes. Cache-Control: no-store.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboundRegistrationSessionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Current attempt state; a grant is present only for verified.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboundRegistrationStatus"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "description": "attempt_not_found for an unknown attempt or incorrect poll token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/inbound/cancel": {
      "post": {
        "tags": ["registration"],
        "summary": "Cancel an incoming attempt",
        "description": "Requires the private polling capability and makes an unused attempt unusable. Provider retries cannot revive it. Returns the resulting status. Request body limit: 1,024 bytes. Cache-Control: no-store.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InboundRegistrationSessionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Attempt status after cancellation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboundRegistrationStatus"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "description": "attempt_not_found for an unknown attempt or incorrect poll token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/inbound/whatsapp": {
      "get": {
        "tags": ["registration"],
        "summary": "Verify the dedicated Meta webhook subscription",
        "description": "Meta setup handshake only. The generated sealed webhook verify token is compared in constant time; it does not authenticate POST callbacks. Returns hub.challenge as plain text after validation. Cache-Control: no-store.",
        "security": [],
        "parameters": [
          {
            "name": "hub.mode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "const": "subscribe"
            }
          },
          {
            "name": "hub.verify_token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            },
            "description": "Generated in Services and disclosed only by an explicit administrator action. Do not log the query."
          },
          {
            "name": "hub.challenge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{1,128}$"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Exact challenge.",
            "headers": {
              "Cache-Control": {
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string",
                  "pattern": "^\\d{1,128}$"
                }
              }
            }
          },
          "400": {
            "description": "webhook_invalid: malformed handshake.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "webhook_invalid: verification token rejected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "webhook_invalid: incoming WhatsApp configuration is incomplete.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": ["registration"],
        "summary": "Receive a signed WhatsApp verification message",
        "description": "Validates the exact raw body before parsing, then matches the dedicated WABA and phone-number ID. Only text events are considered. A phone-based from and matching contact wa_id are required; a hidden number, a BSUID or a number typed in the message is not accepted as phone proof. Challenges are short-lived, single-use and bound to the app attempt, requested number and receiving account. Request body limit: 65,536 bytes.",
        "security": [
          {
            "whatsappWebhookSignature": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhatsAppIncomingWebhook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged. Unrelated but valid events are ignored; a receipt does not by itself mean phone verification succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderWebhookAcknowledgement"
                }
              }
            }
          },
          "400": {
            "description": "webhook_invalid: malformed provider payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "webhook_invalid: missing, invalid or expired callback signature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Request exceeds the endpoint body limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Required receiving configuration or delivery persistence is unavailable; provider may retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/inbound/telnyx": {
      "post": {
        "tags": ["registration"],
        "summary": "Receive signed Telnyx incoming SMS and outgoing delivery events",
        "description": "Stable messaging-profile callback for both directions. Validates Ed25519 signature and timestamp before parsing. message.received additionally requires a configured owned receiving number and exact messaging-profile match; received SMS can require a stronger outgoing proof but never issues a completion grant. message.finalized uses the existing delivery recorder even when no receiving numbers are configured. Other signed event types are acknowledged without action. Body limit: 65,536 bytes; finalized delivery events retain the delivery recorder limit of 16,384 bytes.",
        "security": [
          {
            "telnyxWebhookSignature": []
          }
        ],
        "parameters": [
          {
            "name": "telnyx-timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{10}$"
            },
            "description": "Unix seconds, authenticated with the exact raw payload. Accepted only within five minutes of server time."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelnyxIncomingWebhook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged. Unrelated but valid events are ignored; a receipt does not by itself mean phone verification succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderWebhookAcknowledgement"
                }
              }
            }
          },
          "400": {
            "description": "webhook_invalid: malformed provider payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "webhook_invalid: missing, invalid or expired callback signature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Request exceeds the endpoint body limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Required receiving configuration or delivery persistence is unavailable; provider may retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/telnyx/status": {
      "post": {
        "tags": ["registration"],
        "summary": "Receive a signed Telnyx outgoing SMS delivery report",
        "description": "Backward-compatible delivery-only callback. Existing integrations may retain this URL; new setups can use the unified incoming/telnyx callback. Verifies Ed25519 over timestamp and raw body. Only message.finalized for the configured messaging profile updates delivery status and optional provider cost, once. It does not create or complete a verification proof. Request body limit: 16,384 bytes.",
        "security": [
          {
            "telnyxWebhookSignature": []
          }
        ],
        "parameters": [
          {
            "name": "telnyx-timestamp",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^\\d{10}$"
            },
            "description": "Unix seconds, authenticated with the exact raw payload. Accepted only within five minutes of server time."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TelnyxDeliveryWebhook"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged. Unrelated but valid events are ignored; a receipt does not by itself mean phone verification succeeded.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProviderWebhookAcknowledgement"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request: malformed provider payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "401": {
            "description": "invalid_request: missing, invalid or expired callback signature.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "413": {
            "description": "Request exceeds the endpoint body limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "Required receiving configuration or delivery persistence is unavailable; provider may retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/start": {
      "post": {
        "tags": ["registration"],
        "summary": "Start phone registration through the explicitly selected delivery channel",
        "description": "Optional channel defaults to SMS for legacy clients. WhatsApp and SMS share phone, IP and country quotas. New challenges expire within 600 seconds and are bound to one attempt and channel; a failed delivery burns that attempt. No automatic fallback or second send.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterStartRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delivery accepted by the selected provider, or an operator test attempt admitted. Not proof of delivery or successful verification.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterStartResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "description": "`prefix_blocked` (country blocked) or `attestation_required`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "502": {
            "description": "`sms_provider_failed` or `delivery_provider_failed`. No automatic fallback is attempted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "503": {
            "description": "`sms_not_configured` or `channel_unavailable`: the selected channel is not available under current deployment policy (D63, D90).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/register/verify": {
      "post": {
        "tags": ["registration"],
        "summary": "Verify the registration code and log the device in",
        "description": "Retired (D197). Unless `registration.legacy_matrix_verify` is true (refused for the production origin), every request answers 410 `legacy_registration_retired` before the body or the attempt is read, so no attempt is consumed. New devices use the relay fresh-start route.",
        "deprecated": true,
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterVerifyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Registered (or logged in) and a Matrix access token issued.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterVerifyResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "description": "`attempt_not_found`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "409": {
            "description": "`attempt_expired`, `attempt_burned`, `attempt_consumed` or `code_mismatch`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "410": {
            "description": "`legacy_registration_retired` (D197): the route is off. The attempt is untouched.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/hash-details": {
      "get": {
        "tags": ["app"],
        "summary": "Pepper and algorithm for contact hashing",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HashDetailsResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/v1/contacts/lookup": {
      "post": {
        "tags": ["app"],
        "summary": "Which of these hashed phone numbers are on Natter",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ContactsLookupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Matches only; every match carries a `kind`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContactsLookupResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/v1/link/confirm": {
      "post": {
        "tags": ["app"],
        "summary": "Link this Natter account to a Masons Mail account with a code",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkConfirmRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "`{linked: true}`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["linked"],
                  "properties": {
                    "linked": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "409": {
            "description": "`link_code_invalid`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "`link_unavailable` (no `masonsmail_link_token`) or `masonsmail_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    },
    "/v1/link/invite": {
      "post": {
        "tags": ["app"],
        "summary": "Ask Masons Mail to invite this email address",
        "security": [
          {
            "matrixToken": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LinkInviteRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "`{invited: true}` — forwarded; the address is never stored here.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["invited"],
                  "properties": {
                    "invited": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "description": "`link_unavailable` or `masonsmail_unavailable`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiError"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "message": {
      "post": {
        "summary": "Historical message event vocabulary (delivery unavailable)",
        "description": "Retained for compatibility with historical records only. The Matrix Business webhook worker and its public configuration routes have been removed. This does not describe an active delivery or authorize the private Go replacement.",
        "deprecated": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEnvelope"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Historical receiver acknowledgement; no current delivery service is mounted."
          }
        }
      }
    },
    "status": {
      "post": {
        "summary": "Historical status event vocabulary (delivery unavailable)",
        "description": "Retained for compatibility with historical records only. The Matrix Business webhook worker and its public configuration routes have been removed. This does not describe an active delivery or authorize the private Go replacement.",
        "deprecated": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEnvelope"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Historical receiver acknowledgement; no current delivery service is mounted."
          }
        }
      }
    },
    "opt_out": {
      "post": {
        "summary": "Historical opt_out event vocabulary (delivery unavailable)",
        "description": "Retained for compatibility with historical records only. The Matrix Business webhook worker and its public configuration routes have been removed. This does not describe an active delivery or authorize the private Go replacement.",
        "deprecated": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEnvelope"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Historical receiver acknowledgement; no current delivery service is mounted."
          }
        }
      }
    },
    "opt_in": {
      "post": {
        "summary": "Historical opt_in event vocabulary (delivery unavailable)",
        "description": "Retained for compatibility with historical records only. The Matrix Business webhook worker and its public configuration routes have been removed. This does not describe an active delivery or authorize the private Go replacement.",
        "deprecated": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEnvelope"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Historical receiver acknowledgement; no current delivery service is mounted."
          }
        }
      }
    },
    "policy": {
      "post": {
        "summary": "Historical policy event vocabulary (delivery unavailable)",
        "description": "Retained for compatibility with historical records only. The Matrix Business webhook worker and its public configuration routes have been removed. This does not describe an active delivery or authorize the private Go replacement.",
        "deprecated": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEnvelope"
              }
            }
          }
        },
        "responses": {
          "2XX": {
            "description": "Historical receiver acknowledgement; no current delivery service is mounted."
          }
        }
      }
    }
  }
}
