{"openapi":"3.1.0","info":{"title":"Mittis API","version":"0.1.0","description":"The Mittis API sends and receives text messages and voice calls over carrier-direct numbers, and manages the numbers, 10DLC registrations, call routing, webhooks and billing behind them. It is a JSON REST API served from `https://api.mittis.ai`.\n\n## Authentication\n\nSend your API key as a bearer token:\n\n```\nAuthorization: Bearer sk_live_...\n```\n\nCreate keys in the console or with `POST /v1/keys`. A key is shown once, so store it. `sk_test_...` keys run in **test mode**: messages are stubbed and never reach a carrier, and no campaign is required. Sending from the reserved number `+15005550006` is always a test send, even with a live key.\n\n### Agencies and sub-accounts\n\nAn **agency** key manages child accounts under `/v1/subaccounts` and `/v1/agency/*`. To operate on one sub-account with the whole rest of the API (numbers, messages, webhooks, ...), send the agency key plus the header `Mittis-Subaccount: <sub-account id>`. Agency-level routes reject that header, and a sub-account that is not your direct child returns `403`.\n\n## Errors\n\nEvery error uses one envelope, and the HTTP status always matches the code:\n\n```json\n{ \"error\": { \"code\": \"not_found\", \"message\": \"Message not found.\" } }\n```\n\n| Code | HTTP | Meaning |\n| --- | --- | --- |\n| `validation_error` | 400 | The request failed validation. `details` lists the offending fields. |\n| `unauthorized` | 401 | Missing, malformed, revoked or unknown credentials. |\n| `forbidden` | 403 | The credential is valid but is not allowed to do this. |\n| `not_found` | 404 | The resource does not exist (or belongs to another account). |\n| `conflict` | 409 | The request conflicts with the current state of the resource. |\n| `rate_limited` | 429 | Too many requests. Slow down and retry. |\n| `budget_exceeded` | 402 | The account monthly spend limit has been reached. |\n| `payment_required` | 402 | The prepaid wallet balance is empty. Top it up and retry. |\n| `channel_unsupported` | 422 | The destination or sender cannot be used on this channel. |\n| `address_suggestion` | 422 | The carrier can only place the address after a correction. `details.suggested` carries the corrected address; resubmit it. |\n| `provider_error` | 502 | An upstream carrier or payment provider failed. Safe to retry later. |\n| `internal_error` | 500 | Something went wrong on our end. |\n\nBranch on `error.code`, never on `message`. Validation failures list the offending fields in `error.details` as `[{ \"path\": [...], \"message\": \"...\" }]`.\n\n## Pagination\n\nList endpoints return `{ \"data\": [...], \"hasMore\": false, \"nextCursor\": null }`, newest first. Pass `nextCursor` back as `?cursor=` (and `limit`) to fetch the next, older page. Cursors are opaque. Small bounded lists are returned whole with `hasMore: false`. Where noted, `?format=array` returns a bare array instead.\n\n## Idempotency\n\n`POST /v1/messages` and `POST /v1/ports` accept an `Idempotency-Key` header. A retry with the same key returns the original result (marked `Idempotent-Replayed: true`) instead of repeating the action.\n\n## Money\n\nAll amounts are integer **cents** unless a field name says otherwise.\n\n## Webhooks\n\nConfigure endpoints with `/v1/webhooks`. Events are POSTed as JSON with the event fields at the top level plus `id` and `createdAt`, signed with an HMAC. Delivery is at-least-once with retries, so dedupe on `id`. See the **Webhook events** section for every event and its payload, and the signature scheme. The same events are available by polling `GET /v1/events`.","contact":{"name":"Mittis","url":"https://mittis.ai"}},"servers":[{"url":"https://api.mittis.ai","description":"Production"}],"security":[{"ApiKey":[]}],"tags":[{"name":"Messages","description":"Send texts and read message history."},{"name":"Conversations","description":"Messages grouped by the other party."},{"name":"Blocked numbers","description":"The inbound call blocklist."},{"name":"Numbers","description":"Buy, configure, route, verify and release phone numbers."},{"name":"Brands","description":"10DLC brand registration."},{"name":"Campaigns","description":"10DLC campaign registration."},{"name":"Registration","description":"Combined brand + campaign registration and AI-assisted drafting."},{"name":"Calls","description":"Inbound and outbound voice calls, recordings and transfers."},{"name":"Voicemails","description":"Captured voicemails and their transcripts."},{"name":"Ports","description":"Port numbers in from another carrier."},{"name":"Email domains","description":"Register and verify domains you send email from."},{"name":"Email","description":"Send email from a verified domain and read it back."},{"name":"Softphone","description":"Browser and mobile softphone devices, and placing outbound calls."},{"name":"Webhooks","description":"Manage webhook endpoints and inspect deliveries."},{"name":"Events","description":"A durable polling feed of the events webhooks deliver."},{"name":"API keys","description":"Create, list and revoke API keys."},{"name":"Usage","description":"Metered usage and spend."},{"name":"Billing","description":"Subscription and prepaid wallet."},{"name":"Sub-accounts","description":"Agency-only: manage child accounts."},{"name":"Agency","description":"Agency-only: rollups, statements, wallet and the number fleet."},{"name":"Webhook events","description":"Requests Mittis sends to your endpoints."}],"components":{"responses":{"ValidationError":{"description":"The request failed validation (`validation_error`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"validation_error","message":"Request validation failed."}}}}},"Unauthorized":{"description":"Authentication is missing or invalid (`unauthorized`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"unauthorized","message":"Authentication required."}}}}},"PaymentRequired":{"description":"The monthly spend limit was reached (`budget_exceeded`) or the prepaid wallet is empty (`payment_required`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"payment_required","message":"Monthly spend limit reached for this account."}}}}},"Forbidden":{"description":"The credential is not allowed to perform this action (`forbidden`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"forbidden","message":"Not authorized for that sub-account."}}}}},"NotFound":{"description":"The resource was not found (`not_found`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"not_found","message":"Resource not found."}}}}},"Conflict":{"description":"The request conflicts with the current state of the resource (`conflict`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"conflict","message":"The request conflicts with the current state of this resource."}}}}},"Unprocessable":{"description":"The request was understood but cannot be processed (`channel_unsupported` or `address_suggestion`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"channel_unsupported","message":"The request cannot be processed."}}}}},"RateLimited":{"description":"Too many requests (`rate_limited`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"rate_limited","message":"Too many messages too quickly. Slow down and retry."}}}}},"ProviderError":{"description":"An upstream provider failed (`provider_error`). Safe to retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"provider_error","message":"The upstream provider could not complete the request."}}}}}},"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"sk_live_… / sk_test_…","description":"Your API key, sent as `Authorization: Bearer sk_live_…`. Keys are created in the console or with `POST /v1/keys` and shown exactly once. `sk_test_…` keys run in test mode: messages are stubbed and never reach a carrier."}},"schemas":{"PageEnvelope":{"type":"object","properties":{"hasMore":{"type":"boolean","description":"True when more rows exist beyond this page."},"nextCursor":{"type":["string","null"],"description":"Opaque cursor. Pass it back as `cursor` to fetch the next (older) page; null when there are no more pages."}},"required":["hasMore","nextCursor"],"description":"Pagination fields shared by every list response (`{ data, hasMore, nextCursor }`). Small bounded sets are returned whole with `hasMore: false` and `nextCursor: null`."},"OkResponse":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"],"example":{"ok":true}},"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["validation_error","unauthorized","forbidden","not_found","conflict","rate_limited","budget_exceeded","payment_required","channel_unsupported","address_suggestion","provider_error","internal_error"],"description":"Stable machine-readable code. Branch on this, never on `message`."},"message":{"type":"string","description":"Human-readable explanation, safe to show to an end user."},"details":{"description":"Optional structured detail. For `validation_error` it is an array of `{ path, message }`; for `address_suggestion` it is `{ suggested }`."}},"required":["code","message"]}},"required":["error"],"description":"The single error envelope returned by every endpoint. Raw provider or database errors are never exposed.","example":{"error":{"code":"not_found","message":"Message not found."}}},"Message":{"type":"object","properties":{"id":{"type":"string","description":"Message id."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Destination number (E.164)."},"from":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Sender number (E.164). Must be a number you own."},"body":{"type":"string","description":"Message text. Empty for a media-only MMS."},"direction":{"type":"string","enum":["outbound","inbound"],"description":"`outbound` for messages you sent, `inbound` for replies and incoming texts."},"status":{"type":"string","enum":["queued","sending","sent","delivered","failed","undelivered","received"],"description":"Delivery state. Outbound messages move `queued` → `sending` → `sent` → `delivered` (or `failed` / `undelivered`); inbound messages are `received`."},"segments":{"type":"integer","minimum":0,"description":"Billable SMS segments (160 GSM-7 / 70 UCS-2 characters per segment)."},"channel":{"type":"string","description":"The channel the message travelled on, e.g. `sms`."},"media":{"type":["array","null"],"items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"contentType":{"type":"string"},"filename":{"type":"string"}},"required":["url"]},"description":"MMS attachments; null for a plain SMS."},"createdAt":{"type":"string","description":"When the message was created (ISO 8601)."}},"required":["id","to","from","body","direction","status","segments","channel","media","createdAt"],"description":"A text message, inbound or outbound.","example":{"id":"8f14e45f-ceea-467a-9575-4d2f7b0e2a31","to":"+15555550142","from":"+15555550100","body":"Hi Sam, your appointment is confirmed for Tuesday at 2pm.","direction":"outbound","status":"delivered","segments":1,"channel":"sms","media":null,"createdAt":"2026-07-01T15:04:05.000Z"}},"MessagePage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}},"required":["data"]}],"description":"A page of messages, newest first."},"SendMessageRequest":{"type":"object","properties":{"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Destination number (E.164)."},"from":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Sender number (E.164). Must be one of your own numbers with an approved campaign. The reserved test number `+15005550006` is always stubbed and needs no campaign."},"body":{"type":"string","maxLength":1600,"description":"Message text, up to 1600 characters. Optional only when `mediaUrls` is present (a media-only MMS). A request with neither is rejected with `validation_error`."},"mediaUrls":{"type":"array","items":{"type":"string","format":"uri"},"maxItems":10,"description":"Public URLs to send as MMS attachments (max 10). The carrier fetches each one."}},"required":["to","from"],"description":"Send an outbound message.","example":{"to":"+15555550142","from":"+15555550100","body":"Hi Sam, your appointment is confirmed for Tuesday at 2pm."}},"ConversationSummary":{"type":"object","properties":{"counterparty":{"type":"string","description":"The other party (E.164)."},"lastBody":{"type":"string","description":"Text of the most recent message in the thread."},"lastAt":{"type":"string","description":"When the most recent message was created (ISO 8601)."},"direction":{"type":"string","enum":["outbound","inbound"],"description":"Direction of the most recent message."}},"required":["counterparty","lastBody","lastAt","direction"],"description":"One thread, grouped by counterparty number.","example":{"counterparty":"+15555550142","lastBody":"See you Tuesday!","lastAt":"2026-07-01T15:09:41.000Z","direction":"inbound"}},"ConversationPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ConversationSummary"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"ConversationThread":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Message"},"description":"Messages with this number, oldest first."}},"required":["data"],"description":"The recent message thread with one counterparty."},"BlockedNumber":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid","description":"The account this entry belongs to."},"phoneNumber":{"type":"string","description":"The blocked number (E.164)."},"reason":{"type":["string","null"],"description":"Free-text note shown in the console."},"autoSuggested":{"type":"boolean","description":"True when the entry was suggested automatically and is not enforced until a person confirms it."},"blockedCallCount":{"type":"integer","description":"How many inbound calls this entry has rejected."},"lastBlockedAt":{"type":["string","null"],"description":"When it last rejected a call (ISO 8601)."},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","tenantId","phoneNumber","reason","autoSuggested","blockedCallCount","lastBlockedAt","createdAt","updatedAt"],"description":"A number whose inbound calls are rejected before anything rings. Confirmed (non auto-suggested) entries are enforced.","example":{"id":"3b241101-e2bb-4255-8caf-4136c566a962","tenantId":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11","phoneNumber":"+15555550199","reason":"Robocaller","autoSuggested":false,"blockedCallCount":3,"lastBlockedAt":"2026-07-01T14:00:00.000Z","createdAt":"2026-06-20T10:00:00.000Z","updatedAt":"2026-06-20T10:00:00.000Z"}},"BlockedNumberPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/BlockedNumber"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"PhoneNumber":{"type":"object","properties":{"id":{"type":"string","description":"Number id."},"phoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number (E.164)."},"label":{"type":["string","null"],"description":"Your own name for the number (up to 64 characters), or null. Set with `PATCH /v1/numbers/{id}`."},"route":{"type":["object","null"],"properties":{"kind":{"type":"string","enum":["forward","ring_group","ivr","webhook","voicemail","disabled"]},"label":{"type":"string"}},"required":["kind","label"],"description":"A one-line summary of where inbound calls go, or null when the number has no route. `kind` is `forward`, `ring_group`, `ivr`, `webhook`, `voicemail` or `disabled`; `label` is display text. The full route is `GET /v1/numbers/{id}/route`."},"status":{"type":"string","enum":["live","idle","pending","released"],"description":"`live` (sending, campaign attached), `idle` (owned, not yet attached), `pending`, or `released` (returned to the carrier)."},"type":{"type":"string","enum":["local","tollfree"],"description":"`local` or `tollfree`."},"capabilities":{"type":"object","properties":{"sms":{"type":"boolean"},"mms":{"type":"boolean"},"voice":{"type":"boolean"}},"required":["sms","mms","voice"],"description":"What the number can do."},"campaignId":{"type":["string","null"],"description":"The 10DLC campaign the number is assigned to, or null."},"campaignName":{"type":["string","null"],"description":"Name of that campaign, or null."},"callerIdName":{"type":"object","properties":{"name":{"type":["string","null"]},"status":{"type":"string","enum":["off","pending","active","failed"]}},"required":["name","status"],"description":"Outbound caller-ID name (CNAM listing). `status` is `pending` after you set it; carriers take days to propagate."},"emergency":{"type":"object","properties":{"enabled":{"type":"boolean"},"address":{"type":["object","null"],"properties":{"street":{"type":"string"},"street2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"}},"required":["street","city","state","zip"]},"status":{"type":"string","enum":["off","pending","active","failed"]}},"required":["enabled","address","status"],"description":"Emergency calling (E911). Enabled numbers carry a monthly emergency-calling fee. `address` is the registered dispatch address."},"tfvStatus":{"type":"string","description":"Toll-free verification: `not_applicable` for local numbers, otherwise `unverified`, `pending`, `verified`, `rejected` or `action_required` (the carrier wants more information; resubmit as you would after a rejection)."},"tfvRejectionReason":{"type":["string","null"],"description":"Why the last toll-free verification was rejected, or what the carrier asks you to fix; otherwise null."},"releasedAt":{"type":["string","null"],"description":"When the number was released back to the carrier (ISO 8601), else null."}},"required":["id","phoneNumber","label","route","status","type","capabilities","campaignId","campaignName","callerIdName","emergency","tfvStatus","tfvRejectionReason","releasedAt"],"description":"A phone number you own.","example":{"id":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d","phoneNumber":"+15555550100","label":"Main line","route":{"kind":"forward","label":"Rings Front desk"},"status":"live","type":"local","capabilities":{"sms":true,"mms":true,"voice":true},"campaignId":"7c9e6679-7425-40de-944b-e07fc1f90ae7","campaignName":"Appointment reminders","callerIdName":{"name":"ACME PLUMBING","status":"active"},"emergency":{"enabled":true,"address":{"street":"123 Main St","city":"Richmond","state":"VA","zip":"23219"},"status":"active"},"tfvStatus":"not_applicable","tfvRejectionReason":null,"releasedAt":null}},"PhoneNumberPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PhoneNumber"}}},"required":["data"]}],"description":"A page of numbers."},"AvailableNumber":{"type":"object","properties":{"phoneNumber":{"type":"string","description":"The number (E.164)."},"type":{"type":"string","enum":["local","tollfree"]},"capabilities":{"type":"object","properties":{"sms":{"type":"boolean"},"mms":{"type":"boolean"},"voice":{"type":"boolean"}},"required":["sms","mms","voice"]},"monthlyPriceCents":{"type":"integer","description":"What you are billed per month to rent this number, in cents."}},"required":["phoneNumber","type","capabilities","monthlyPriceCents"],"description":"A number that can be purchased.","example":{"phoneNumber":"+15555550123","type":"local","capabilities":{"sms":true,"mms":true,"voice":true},"monthlyPriceCents":165}},"AvailableNumberPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AvailableNumber"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"CallRoute":{"type":"object","properties":{"id":{"type":"string","description":"Route id."},"destinationType":{"type":"string","enum":["sip","pstn","webrtc"],"description":"Type of the primary destination: `sip`, `pstn` or `webrtc` (a softphone device id)."},"destination":{"type":"string","description":"The primary (priority 0) destination. Mirrors `destinations[0]`."},"ringTimeoutSecs":{"type":"integer","description":"Ring timeout of the primary destination."},"enabled":{"type":"boolean","description":"Whether the route is active."},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"description":"`simultaneous` rings every destination at once, `sequential` one at a time in priority order, `staged` rings each `stage` as a wave."},"callerIdMode":{"type":"string","enum":["caller","business"],"description":"`caller` shows the original caller to destinations, `business` shows the number being called."},"destinations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string"},"label":{"type":["string","null"]},"priority":{"type":"integer"},"stage":{"type":"integer"},"ringTimeoutSecs":{"type":"integer"},"enabled":{"type":"boolean"}},"required":["id","destinationType","destination","label","priority","stage","ringTimeoutSecs","enabled"]},"minItems":1,"description":"The full ordered ring set (priority 0 is primary)."},"recordCalls":{"type":"boolean","description":"Record answered calls; a `call.transcript` event follows each recorded call."},"liveTranscription":{"type":"boolean","description":"Stream `call.transcript.delta` events while an answered call is bridged. Billed per minute, so opt-in."},"voicemailEnabled":{"type":"boolean","description":"Capture voicemail when nobody answers (`voicemail.received` follows)."},"voicemailGreeting":{"type":["string","null"],"description":"Greeting text spoken before the beep; null uses the default."},"voicemailGreetingAudioUrl":{"type":["string","null"],"description":"Public URL of a custom greeting recording, played instead of the text greeting. Managed with `PUT /v1/numbers/{id}/voicemail-greeting`."},"noAnswerAction":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["forward"]},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},"required":["type","to"]},{"type":"null"}],"description":"What happens when nobody answers; null means voicemail when enabled, else the call rings out."},"outboundRingTimeoutSecs":{"type":["integer","null"],"description":"Ring timeout for outbound calls placed from this number; null uses the default."},"recordingNotice":{"type":["object","null"],"properties":{"text":{"type":"string","minLength":1,"maxLength":500},"audioUrl":{"type":"string","maxLength":1000,"format":"uri"}},"description":"Notice played to the caller before connecting when `recordCalls` is on; null for none."},"ivr":{"type":["object","null"],"properties":{"enabled":{"type":"boolean"},"greeting":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":1000},"audioUrl":{"type":"string","maxLength":1000,"format":"uri"}}},"digitTimeoutSecs":{"type":"integer","minimum":1,"maximum":30,"default":5},"invalidRetries":{"type":"integer","minimum":0,"maximum":5,"default":1},"keys":{"type":"array","items":{"type":"object","properties":{"digit":{"type":"string","pattern":"^[0-9*#]$"},"label":{"type":["string","null"],"minLength":1,"maxLength":80},"action":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["ring"]},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"default":"simultaneous"},"destinations":{"type":"array","items":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string","minLength":3,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":80},"stage":{"type":"integer","minimum":0,"maximum":4,"default":0},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25},"enabled":{"type":"boolean","default":true}},"required":["destinationType","destination"]},"minItems":1,"maxItems":10}},"required":["type","destinations"]},{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["repeat"]}},"required":["type"]}]}},"required":["digit","action"]},"minItems":1,"maxItems":12},"fallback":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["ring"]},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"default":"simultaneous"},"destinations":{"type":"array","items":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string","minLength":3,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":80},"stage":{"type":"integer","minimum":0,"maximum":4,"default":0},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25},"enabled":{"type":"boolean","default":true}},"required":["destinationType","destination"]},"minItems":1,"maxItems":10}},"required":["type","destinations"]},{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["repeat"]}},"required":["type"]}],"default":{"type":"voicemail"}}},"required":["enabled","greeting","keys"],"description":"Declarative IVR menu; null for none."},"decisionWebhook":{"type":["object","null"],"properties":{"enabled":{"type":"boolean"},"url":{"type":"string","maxLength":1000,"format":"uri"},"timeoutMs":{"type":"integer","minimum":100,"maximum":5000,"default":800}},"required":["enabled","url"],"description":"Synchronous per-call routing decision webhook; null when not configured. See the `call.routing.decision` webhook."}},"required":["id","destinationType","destination","ringTimeoutSecs","enabled","ringMode","callerIdMode","destinations","recordCalls","liveTranscription","voicemailEnabled","voicemailGreeting","voicemailGreetingAudioUrl","noAnswerAction","outboundRingTimeoutSecs","recordingNotice","ivr","decisionWebhook"],"description":"Where a number's inbound calls ring. The top-level destination fields always mirror the primary destination; the full ring set is in `destinations`."},"CallRouteResponse":{"type":"object","properties":{"route":{"allOf":[{"$ref":"#/components/schemas/CallRoute"},{"type":["object","null"]}]},"features":{"type":"array","items":{"type":"string","enum":["ivr","decisionWebhook","recordingNotice"]},"description":"Route features this deployment supports; gate your UI on them."}},"required":["route","features"],"description":"A number route plus the supported feature list."},"CallRouteWrite":{"type":"object","properties":{"route":{"$ref":"#/components/schemas/CallRoute"}},"required":["route"],"description":"The saved route."},"UpdateCallRouteRequest":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"],"description":"Legacy single-destination form: type of the destination."},"destination":{"type":"string","minLength":3,"maxLength":200,"description":"Legacy single-destination form: a PSTN number (E.164), a `sip:` URI, or the id of one of your softphone devices (`webrtc`)."},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25,"description":"Ring timeout (5-120s) for the legacy single-destination form."},"enabled":{"type":"boolean","default":true,"description":"Whether the route is active."},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"default":"simultaneous"},"callerIdMode":{"type":"string","enum":["caller","business"],"default":"caller"},"recordCalls":{"type":"boolean","default":false},"liveTranscription":{"type":"boolean","default":false},"voicemailEnabled":{"type":"boolean","default":false},"voicemailGreeting":{"type":["string","null"],"minLength":1,"maxLength":500,"description":"Greeting text (max 500 characters)."},"destinations":{"type":"array","items":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string","minLength":3,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":80},"stage":{"type":"integer","minimum":0,"maximum":4,"default":0},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25},"enabled":{"type":"boolean","default":true}},"required":["destinationType","destination"]},"minItems":0,"maxItems":10,"description":"The full replacement ring set (max 10). Wins over the legacy fields. An explicit empty array keeps only the route settings (e.g. a voicemail-only number)."},"noAnswerAction":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["forward"]},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},"required":["type","to"]},{"type":"null"}],"description":"`{ type: \"voicemail\" }` or `{ type: \"forward\", to }`. Null clears."},"outboundRingTimeoutSecs":{"type":["integer","null"],"minimum":5,"maximum":120,"description":"Outbound ring timeout (5-120s). Null clears."},"recordingNotice":{"type":["object","null"],"properties":{"text":{"type":"string","minLength":1,"maxLength":500},"audioUrl":{"type":"string","maxLength":1000,"format":"uri"}},"description":"Provide `text` or `audioUrl`. Null clears."},"ivr":{"type":["object","null"],"properties":{"enabled":{"type":"boolean"},"greeting":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":1000},"audioUrl":{"type":"string","maxLength":1000,"format":"uri"}}},"digitTimeoutSecs":{"type":"integer","minimum":1,"maximum":30,"default":5},"invalidRetries":{"type":"integer","minimum":0,"maximum":5,"default":1},"keys":{"type":"array","items":{"type":"object","properties":{"digit":{"type":"string","pattern":"^[0-9*#]$"},"label":{"type":["string","null"],"minLength":1,"maxLength":80},"action":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["ring"]},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"default":"simultaneous"},"destinations":{"type":"array","items":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string","minLength":3,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":80},"stage":{"type":"integer","minimum":0,"maximum":4,"default":0},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25},"enabled":{"type":"boolean","default":true}},"required":["destinationType","destination"]},"minItems":1,"maxItems":10}},"required":["type","destinations"]},{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["repeat"]}},"required":["type"]}]}},"required":["digit","action"]},"minItems":1,"maxItems":12},"fallback":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["ring"]},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"default":"simultaneous"},"destinations":{"type":"array","items":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string","minLength":3,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":80},"stage":{"type":"integer","minimum":0,"maximum":4,"default":0},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25},"enabled":{"type":"boolean","default":true}},"required":["destinationType","destination"]},"minItems":1,"maxItems":10}},"required":["type","destinations"]},{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["repeat"]}},"required":["type"]}],"default":{"type":"voicemail"}}},"required":["enabled","greeting","keys"],"description":"IVR menu. Null clears."},"decisionWebhook":{"type":["object","null"],"properties":{"enabled":{"type":"boolean"},"url":{"type":"string","maxLength":1000,"format":"uri"},"timeoutMs":{"type":"integer","minimum":100,"maximum":5000,"default":800}},"required":["enabled","url"],"description":"Decision webhook config. Null clears."}},"description":"Replaces the number route wholesale (PUT): fields you omit fall back to their defaults and optional objects you omit are cleared. Provide either `destinationType` + `destination`, or a `destinations` array.","example":{"enabled":true,"ringMode":"simultaneous","destinations":[{"destinationType":"pstn","destination":"+15555550150","ringTimeoutSecs":25}],"recordCalls":false,"voicemailEnabled":true}},"VoicemailGreeting":{"type":"object","properties":{"greetingAudioUrl":{"type":"string","description":"Public URL of the stored greeting. A new URL is minted on every upload."}},"required":["greetingAudioUrl"],"example":{"greetingAudioUrl":"https://api.mittis.ai/media/greetings/4f2c1a9e"}},"Brand":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid","description":"The account that owns the brand."},"legalName":{"type":"string","description":"Legal business name."},"displayName":{"type":["string","null"],"description":"Name shown to consumers, when different."},"ein":{"type":["string","null"],"description":"Tax id."},"website":{"type":["string","null"]},"vertical":{"type":["string","null"],"description":"Industry vertical."},"status":{"type":"string","enum":["draft","submitted","approved","rejected"],"description":"Registration state: `draft`, `submitted`, `approved` or `rejected`."},"tcrBrandId":{"type":["string","null"],"description":"The registry brand id once registered."},"mock":{"type":"boolean","description":"True for a free test brand (campaigns under it are mock)."},"entityType":{"type":["string","null"],"description":"`PRIVATE_PROFIT`, `PUBLIC_PROFIT`, `NON_PROFIT`, `GOVERNMENT` or `SOLE_PROPRIETOR`."},"einIssuingCountry":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"street":{"type":["string","null"]},"city":{"type":["string","null"]},"state":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"country":{"type":["string","null"]},"businessContactEmail":{"type":["string","null"]},"stockSymbol":{"type":["string","null"]},"stockExchange":{"type":["string","null"]},"brandRelationship":{"type":["string","null"]},"altBusinessId":{"type":["string","null"]},"altBusinessIdType":{"type":["string","null"]},"identityStatus":{"type":["string","null"],"description":"Identity verification outcome: `SELF_DECLARED`, `UNVERIFIED`, `VERIFIED` or `VETTED_VERIFIED`."},"vettingProvider":{"type":["string","null"]},"vettingClass":{"type":["string","null"]},"vettingScore":{"type":["integer","null"]},"carrierSuspended":{"type":["object","null"],"additionalProperties":{"type":"boolean"},"description":"Per-carrier suspension flags."},"compliancePages":{"type":["object","null"],"properties":{"optIn":{"type":"string"},"privacy":{"type":"string"},"messagingTerms":{"type":"string"}},"required":["optIn","privacy","messagingTerms"],"description":"Copy of the hosted compliance pages."},"pageConfig":{"type":["object","null"],"additionalProperties":{},"description":"Design of the hosted opt-in landing page (see `PATCH /v1/brands/{id}`)."},"complianceUrls":{"type":["object","null"],"properties":{"optInUrl":{"type":"string","description":"Public opt-in landing page."},"privacyUrl":{"type":"string","description":"Public privacy policy page."},"messagingTermsUrl":{"type":"string","description":"Public messaging terms page."}},"required":["optInUrl","privacyUrl","messagingTermsUrl"],"description":"Hosted compliance page URLs. Present on brand reads, creates and updates; omitted on resubmit/vetting/registration responses."},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"required":["id","tenantId","legalName","displayName","ein","website","vertical","status","tcrBrandId","mock","entityType","einIssuingCountry","email","phone","street","city","state","postalCode","country","businessContactEmail","stockSymbol","stockExchange","brandRelationship","altBusinessId","altBusinessIdType","identityStatus","vettingProvider","vettingClass","vettingScore","carrierSuspended","compliancePages","pageConfig","createdAt","updatedAt"],"description":"A brand registered (or being registered) for 10DLC messaging.","example":{"id":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718","tenantId":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11","legalName":"Acme Plumbing LLC","displayName":"Acme Plumbing","ein":"12-3456789","website":"https://example.com","vertical":"PROFESSIONAL","status":"approved","tcrBrandId":"BXXXXXX","mock":false,"entityType":"PRIVATE_PROFIT","einIssuingCountry":"US","email":"owner@example.com","phone":"+15555550100","street":"123 Main St","city":"Richmond","state":"VA","postalCode":"23219","country":"US","businessContactEmail":"owner@example.com","stockSymbol":null,"stockExchange":null,"brandRelationship":"BASIC_ACCOUNT","altBusinessId":null,"altBusinessIdType":null,"identityStatus":"VERIFIED","vettingProvider":null,"vettingClass":null,"vettingScore":null,"carrierSuspended":null,"compliancePages":null,"pageConfig":null,"complianceUrls":{"optInUrl":"https://app.example.com/b/BXXXXXX/opt-in","privacyUrl":"https://app.example.com/b/BXXXXXX/privacy","messagingTermsUrl":"https://app.example.com/b/BXXXXXX/messaging-terms"},"createdAt":"2026-06-01T12:00:00.000Z","updatedAt":"2026-06-02T09:30:00.000Z"}},"BrandPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Brand"}}},"required":["data"]}],"description":"A page of brands, newest first."},"Campaign":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid","description":"The account that owns the campaign."},"brandId":{"type":"string","format":"uuid"},"name":{"type":"string"},"useCase":{"type":"string","description":"The registered use case, e.g. `LOW_VOLUME`."},"status":{"type":"string","enum":["draft","submitted","dca_review","approved","rejected"],"description":"`draft`, `submitted`, `dca_review`, `approved` or `rejected`."},"tcrCampaignId":{"type":["string","null"],"description":"The registry campaign id once registered."},"sampleMessages":{"type":"array","items":{"type":"string"}},"optInDetails":{"type":["string","null"]},"ctaDetails":{"type":["string","null"]},"description":{"type":["string","null"]},"subUsecases":{"type":["array","null"],"items":{"type":"string"}},"subscriberOptin":{"type":["boolean","null"]},"subscriberOptout":{"type":["boolean","null"]},"subscriberHelp":{"type":["boolean","null"]},"embeddedLink":{"type":["boolean","null"]},"embeddedPhone":{"type":["boolean","null"]},"numberPool":{"type":["boolean","null"]},"ageGated":{"type":["boolean","null"]},"directLending":{"type":["boolean","null"]},"affiliateMarketing":{"type":["boolean","null"]},"termsAndConditions":{"type":["boolean","null"]},"optinKeywords":{"type":["string","null"]},"optinMessage":{"type":["string","null"]},"optoutKeywords":{"type":["string","null"]},"optoutMessage":{"type":["string","null"]},"helpKeywords":{"type":["string","null"]},"helpMessage":{"type":["string","null"]},"privacyPolicyLink":{"type":["string","null"]},"termsAndConditionsLink":{"type":["string","null"]},"websiteUrl":{"type":["string","null"]},"mnoMetadata":{"type":["object","null"],"additionalProperties":{},"description":"Per-carrier approval and throughput details."},"cnpSharingStatus":{"type":["string","null"],"description":"Whether the campaign has been shared with the carrier: `none`, `pending`, `accepted` or `declined`."},"remediationAttempts":{"type":"integer","description":"How many times a rejected campaign was rewritten and resubmitted."},"lastRejectionReason":{"type":["string","null"]},"createdAt":{"type":"string","description":"ISO 8601."},"updatedAt":{"type":"string","description":"ISO 8601."}},"required":["id","tenantId","brandId","name","useCase","status","tcrCampaignId","sampleMessages","optInDetails","ctaDetails","description","subUsecases","subscriberOptin","subscriberOptout","subscriberHelp","embeddedLink","embeddedPhone","numberPool","ageGated","directLending","affiliateMarketing","termsAndConditions","optinKeywords","optinMessage","optoutKeywords","optoutMessage","helpKeywords","helpMessage","privacyPolicyLink","termsAndConditionsLink","websiteUrl","mnoMetadata","cnpSharingStatus","remediationAttempts","lastRejectionReason","createdAt","updatedAt"],"description":"A 10DLC messaging campaign registered under a brand.","example":{"id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","tenantId":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11","brandId":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718","name":"Appointment reminders","useCase":"LOW_VOLUME","status":"approved","tcrCampaignId":"CXXXXXX","sampleMessages":["Hi Sam, your appointment is Tuesday at 2pm. Reply STOP to opt out."],"optInDetails":"Customers opt in on our website booking form.","ctaDetails":null,"description":"Appointment reminders and service updates for existing customers.","subUsecases":null,"subscriberOptin":true,"subscriberOptout":true,"subscriberHelp":true,"embeddedLink":false,"embeddedPhone":false,"numberPool":false,"ageGated":false,"directLending":false,"affiliateMarketing":false,"termsAndConditions":true,"optinKeywords":"START","optinMessage":null,"optoutKeywords":"STOP","optoutMessage":null,"helpKeywords":"HELP","helpMessage":null,"privacyPolicyLink":"https://example.com/privacy","termsAndConditionsLink":"https://example.com/terms","websiteUrl":"https://example.com","mnoMetadata":null,"cnpSharingStatus":"accepted","remediationAttempts":0,"lastRejectionReason":null,"createdAt":"2026-06-01T12:05:00.000Z","updatedAt":"2026-06-02T09:30:00.000Z"}},"CampaignSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"useCase":{"type":"string"},"status":{"type":"string","enum":["draft","submitted","dca_review","approved","rejected"]},"tcrCampaignId":{"type":["string","null"]},"cnpSharingStatus":{"type":["string","null"]},"brandName":{"type":["string","null"],"description":"Legal name of the campaign’s brand."},"numbers":{"type":"integer","description":"How many numbers are assigned to the campaign."}},"required":["id","name","useCase","status","tcrCampaignId","cnpSharingStatus","brandName","numbers"],"description":"One row of the campaign list.","example":{"id":"7c9e6679-7425-40de-944b-e07fc1f90ae7","name":"Appointment reminders","useCase":"LOW_VOLUME","status":"approved","tcrCampaignId":"CXXXXXX","cnpSharingStatus":"accepted","brandName":"Acme Plumbing LLC","numbers":2}},"CampaignSummaryPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/CampaignSummary"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"BrandRegistrationRequest":{"type":"object","properties":{"legalName":{"type":"string","minLength":1,"description":"Legal business name. The only required field; the rest raise the approval rate."},"ein":{"type":"string","description":"Tax id (EIN)."},"website":{"type":"string","description":"Business website."},"vertical":{"type":"string","description":"Industry vertical."},"displayName":{"type":"string","description":"Name shown to consumers."},"entityType":{"type":"string","enum":["PRIVATE_PROFIT","PUBLIC_PROFIT","NON_PROFIT","GOVERNMENT","SOLE_PROPRIETOR"],"description":"`PRIVATE_PROFIT`, `PUBLIC_PROFIT`, `NON_PROFIT`, `GOVERNMENT` or `SOLE_PROPRIETOR`."},"einIssuingCountry":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"businessContactEmail":{"type":"string"},"stockSymbol":{"type":"string"},"stockExchange":{"type":"string"},"brandRelationship":{"type":"string","enum":["BASIC_ACCOUNT","SMALL_ACCOUNT","MEDIUM_ACCOUNT","LARGE_ACCOUNT","KEY_ACCOUNT"]},"altBusinessId":{"type":"string"},"altBusinessIdType":{"type":"string"},"mock":{"type":"boolean","description":"Register a free test brand (no charge, no vetting). Campaigns under it are mock and cannot be shared."}},"required":["legalName"],"example":{"legalName":"Acme Plumbing LLC","displayName":"Acme Plumbing","ein":"12-3456789","website":"https://example.com","vertical":"PROFESSIONAL","entityType":"PRIVATE_PROFIT","email":"owner@example.com","phone":"+15555550100","street":"123 Main St","city":"Richmond","state":"VA","postalCode":"23219","country":"US"}},"CampaignCreateRequest":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Campaign name."},"useCase":{"type":"string","minLength":1,"description":"Registered use case, e.g. `LOW_VOLUME`."},"description":{"type":"string","minLength":1,"description":"What the campaign sends and why."},"sampleMessages":{"type":"array","items":{"type":"string"},"minItems":1,"description":"At least one sample message."},"optInDetails":{"type":"string","minLength":1,"description":"How consumers opt in."},"ctaDetails":{"type":"string"},"subUsecases":{"type":"array","items":{"type":"string"}},"subscriberOptin":{"type":"boolean"},"subscriberOptout":{"type":"boolean"},"subscriberHelp":{"type":"boolean"},"embeddedLink":{"type":"boolean"},"embeddedPhone":{"type":"boolean"},"numberPool":{"type":"boolean"},"ageGated":{"type":"boolean"},"directLending":{"type":"boolean"},"affiliateMarketing":{"type":"boolean"},"termsAndConditions":{"type":"boolean"},"optinKeywords":{"type":"string"},"optinMessage":{"type":"string"},"optoutKeywords":{"type":"string"},"optoutMessage":{"type":"string"},"helpKeywords":{"type":"string"},"helpMessage":{"type":"string"},"privacyPolicyLink":{"type":"string"},"termsAndConditionsLink":{"type":"string"},"websiteUrl":{"type":"string"},"brandId":{"type":"string","format":"uuid","description":"The brand to register the campaign under."}},"required":["name","useCase","description","sampleMessages","optInDetails","brandId"],"example":{"brandId":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718","name":"Appointment reminders","useCase":"LOW_VOLUME","description":"Appointment reminders and service updates for existing customers.","sampleMessages":["Hi Sam, your appointment is Tuesday at 2pm. Reply STOP to opt out."],"optInDetails":"Customers opt in on our website booking form."}},"RegistrationRequest":{"type":"object","properties":{"brand":{"type":"object","properties":{"legalName":{"type":"string","minLength":1},"ein":{"type":"string"},"website":{"type":"string"},"vertical":{"type":"string"},"displayName":{"type":"string"},"entityType":{"type":"string","enum":["PRIVATE_PROFIT","PUBLIC_PROFIT","NON_PROFIT","GOVERNMENT","SOLE_PROPRIETOR"]},"einIssuingCountry":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"businessContactEmail":{"type":"string"},"stockSymbol":{"type":"string"},"stockExchange":{"type":"string"},"brandRelationship":{"type":"string","enum":["BASIC_ACCOUNT","SMALL_ACCOUNT","MEDIUM_ACCOUNT","LARGE_ACCOUNT","KEY_ACCOUNT"]},"altBusinessId":{"type":"string"},"altBusinessIdType":{"type":"string"},"mock":{"type":"boolean"}},"required":["legalName"]},"campaign":{"type":"object","properties":{"name":{"type":"string","minLength":1},"useCase":{"type":"string","minLength":1},"description":{"type":"string","minLength":1},"sampleMessages":{"type":"array","items":{"type":"string"},"minItems":1},"optInDetails":{"type":"string","minLength":1},"ctaDetails":{"type":"string"},"subUsecases":{"type":"array","items":{"type":"string"}},"subscriberOptin":{"type":"boolean"},"subscriberOptout":{"type":"boolean"},"subscriberHelp":{"type":"boolean"},"embeddedLink":{"type":"boolean"},"embeddedPhone":{"type":"boolean"},"numberPool":{"type":"boolean"},"ageGated":{"type":"boolean"},"directLending":{"type":"boolean"},"affiliateMarketing":{"type":"boolean"},"termsAndConditions":{"type":"boolean"},"optinKeywords":{"type":"string"},"optinMessage":{"type":"string"},"optoutKeywords":{"type":"string"},"optoutMessage":{"type":"string"},"helpKeywords":{"type":"string"},"helpMessage":{"type":"string"},"privacyPolicyLink":{"type":"string"},"termsAndConditionsLink":{"type":"string"},"websiteUrl":{"type":"string"}},"required":["name","useCase","description","sampleMessages","optInDetails"]}},"required":["brand","campaign"],"description":"A brand and a campaign registered together in one call."},"RegistrationResult":{"type":"object","properties":{"brand":{"$ref":"#/components/schemas/Brand"},"campaign":{"$ref":"#/components/schemas/Campaign"}},"required":["brand","campaign"],"description":"The created brand and campaign."},"BusinessInfo":{"type":"object","properties":{"legalName":{"type":"string","minLength":1,"description":"Legal business name."},"ein":{"type":"string"},"website":{"type":"string"},"vertical":{"type":"string"},"description":{"type":"string","minLength":1,"description":"What the business does and what it texts about."},"optInChannel":{"type":"string","description":"How consumers opt in (e.g. website form, in person)."}},"required":["legalName","description"],"example":{"legalName":"Acme Plumbing LLC","website":"https://example.com","vertical":"PROFESSIONAL","description":"Residential plumbing; we text appointment reminders to existing customers.","optInChannel":"website form"}},"ApprovalPrediction":{"type":"object","properties":{"score":{"type":"number","minimum":0,"maximum":100,"description":"Approval likelihood, 0-100."},"band":{"type":"string","enum":["low","medium","high"],"description":"`low`, `medium` or `high`."},"checks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"passed":{"type":"boolean"}},"required":["id","label","passed"]},"description":"The individual compliance checks."},"suggestions":{"type":"array","items":{"type":"string"},"description":"What to change to improve the score."}},"required":["score","band","checks","suggestions"]},"RegistrationDraft":{"type":"object","properties":{"brand":{"type":"object","properties":{"legalName":{"type":"string"},"ein":{"type":"string"},"website":{"type":"string"},"vertical":{"type":"string"}},"required":["legalName","vertical"]},"campaign":{"type":"object","properties":{"name":{"type":"string"},"useCase":{"type":"string"},"description":{"type":"string"}},"required":["name","useCase","description"]},"sampleMessages":{"type":"array","items":{"type":"string"},"minItems":1},"optInDetails":{"type":"string"},"ctaDetails":{"type":"string"}},"required":["brand","campaign","sampleMessages","optInDetails","ctaDetails"],"description":"A brand and campaign draft ready to review and submit."},"RegistrationDraftResult":{"type":"object","properties":{"draft":{"$ref":"#/components/schemas/RegistrationDraft"},"prediction":{"$ref":"#/components/schemas/ApprovalPrediction"},"iterations":{"type":"integer","description":"How many automatic fix passes ran."}},"required":["draft","prediction","iterations"]},"Call":{"type":"object","properties":{"id":{"type":"string","description":"Call id."},"direction":{"type":"string","enum":["inbound","outbound"],"description":"`inbound` for a call that arrived at one of your numbers, `outbound` for one you placed."},"from":{"type":"string","description":"Caller id as reported by the carrier. Not guaranteed to be E.164 (may be `anonymous`)."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number that was called (E.164)."},"forwardedFrom":{"type":["string","null"],"description":"The original number when the call was forwarded to you; otherwise null."},"contactId":{"type":["string","null"],"description":"Matching contact id, when the caller is a known contact."},"contactName":{"type":["string","null"],"description":"Matching contact name."},"status":{"type":"string","description":"Call state, e.g. `ringing`, `answered`, `completed`, `missed`, `busy`, `failed`, `voicemail`. The vocabulary can grow; treat unknown values as neutral."},"answeredBy":{"type":["string","null"],"description":"Which ring-group destination answered (its label, else the destination); null if unanswered."},"hangupCause":{"type":["string","null"],"description":"Why the call ended, when reported."},"startedAt":{"type":"string","description":"When the call started (ISO 8601)."},"ringingAt":{"type":["string","null"],"description":"When it began ringing (ISO 8601)."},"answeredAt":{"type":["string","null"],"description":"When it was answered (ISO 8601)."},"endedAt":{"type":["string","null"],"description":"When it ended (ISO 8601)."},"durationSeconds":{"type":["number","null"],"description":"Talk time in seconds."},"routing":{"type":["object","null"],"properties":{"type":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string"},"timeoutSecs":{"type":"number"},"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"]},"destinationCount":{"type":"integer"}},"required":["type","destination","timeoutSecs"],"description":"How the call was routed: destination type and value, ring timeout and ring mode."},"recording":{"type":["object","null"],"properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["call","voicemail"]},"status":{"type":"string","enum":["pending","saved","failed"]},"durationSeconds":{"type":["number","null"]},"transcriptStatus":{"type":"string","enum":["pending","available","failed"]},"transcript":{"type":["string","null"]},"transcriptTurns":{"type":["array","null"],"items":{"type":"object","properties":{"speaker":{"type":"string","enum":["caller","rep"]},"text":{"type":"string"}},"required":["speaker","text"]}},"recordingUrl":{"type":["string","null"]}},"required":["id","kind","status","durationSeconds","transcriptStatus","transcript","recordingUrl"],"description":"Recording and transcript, when the call was recorded or captured a voicemail. The transcript arrives asynchronously after the call ends."}},"required":["id","direction","from","to","forwardedFrom","contactId","contactName","status","answeredBy","hangupCause","startedAt","ringingAt","answeredAt","endedAt","durationSeconds","routing"],"description":"A native inbound or human-outbound voice call. Matches the resource the `call.*` webhooks describe.","example":{"id":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","direction":"inbound","from":"+15555550142","to":"+15555550100","forwardedFrom":null,"contactId":null,"contactName":"Sam Rivera","status":"completed","answeredBy":"Front desk","hangupCause":"normal_clearing","startedAt":"2026-07-01T15:00:00.000Z","ringingAt":"2026-07-01T15:00:01.000Z","answeredAt":"2026-07-01T15:00:09.000Z","endedAt":"2026-07-01T15:03:30.000Z","durationSeconds":201,"routing":{"type":"pstn","destination":"+15555550150","timeoutSecs":25},"recording":{"id":"4a3b2c1d-0e9f-4a8b-8c7d-6e5f4a3b2c1d","kind":"call","status":"saved","durationSeconds":201,"transcriptStatus":"available","transcript":"Thanks for calling Acme Plumbing...","transcriptTurns":[{"speaker":"rep","text":"Thanks for calling Acme Plumbing."}],"recordingUrl":"/v1/calls/0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8/recording"}}},"CallPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Call"}}},"required":["data"]}],"description":"A page of calls, newest first."},"Voicemail":{"type":"object","properties":{"id":{"type":"string","description":"Voicemail id."},"callId":{"type":"string","description":"The call that produced it."},"from":{"type":"string","description":"Caller id as reported by the carrier."},"to":{"type":"string","description":"The number that was called (E.164)."},"status":{"type":"string","enum":["pending","saved","failed"],"description":"Whether the audio has finished saving."},"durationSeconds":{"type":["number","null"],"description":"Message length; null if the carrier never reported one."},"transcriptStatus":{"type":"string","enum":["pending","available","failed"],"description":"Transcription is asynchronous: `pending` until it completes."},"transcript":{"type":["string","null"],"description":"Transcript text, once `available`."},"recordingUrl":{"type":["string","null"],"description":"Authenticated path of the audio (`GET /v1/voicemails/{id}/audio`); null until saved."},"receivedAt":{"type":"string","description":"When the caller finished the message (ISO 8601)."}},"required":["id","callId","from","to","status","durationSeconds","transcriptStatus","transcript","recordingUrl","receivedAt"],"description":"A captured voicemail with its transcript.","example":{"id":"9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","status":"saved","durationSeconds":24,"transcriptStatus":"available","transcript":"Hi, this is Sam, calling about the leak under my sink. Please call me back.","recordingUrl":"/v1/voicemails/9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d/audio","receivedAt":"2026-07-01T16:20:00.000Z"}},"VoicemailPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Voicemail"}}},"required":["data"]}],"description":"A page of voicemails, newest first."},"MessageReceivedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["message.received"]},"messageId":{"type":"string"},"from":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"body":{"type":"string"},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"contentType":{"type":"string"},"filename":{"type":"string"}},"required":["url"]}},"receivedAt":{"type":"string"},"providerMessageId":{"type":"string"}},"required":["type","messageId","from","to","body","receivedAt","providerMessageId"],"description":"Inbound message received. Fired when a consumer texts one of your numbers. Fetch the full message with `GET /v1/messages/{messageId}`.","example":{"type":"message.received","messageId":"8f14e45f-ceea-467a-9575-4d2f7b0e2a31","from":"+15555550142","to":"+15555550100","body":"Yes, Tuesday works!","receivedAt":"2026-07-01T15:09:41.000Z","providerMessageId":"msg_5f8e2c1a"}},"MessageReceivedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/MessageReceivedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"Inbound message received, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"message.received","messageId":"8f14e45f-ceea-467a-9575-4d2f7b0e2a31","from":"+15555550142","to":"+15555550100","body":"Yes, Tuesday works!","receivedAt":"2026-07-01T15:09:41.000Z","providerMessageId":"msg_5f8e2c1a","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"MessageStatusEvent":{"type":"object","properties":{"type":{"type":"string","enum":["message.status"]},"messageId":{"type":"string"},"status":{"type":"string","enum":["queued","sending","sent","delivered","failed","undelivered","received"]},"reason":{"type":["string","null"]}},"required":["type","messageId","status","reason"],"description":"Message delivery status changed. Fired as an outbound message moves through its delivery states (`sent`, `delivered`, `failed`, `undelivered`). `reason` carries a sanitized failure reason when the carrier reported one.","example":{"type":"message.status","messageId":"8f14e45f-ceea-467a-9575-4d2f7b0e2a31","status":"delivered","reason":null}},"MessageStatusEventDelivery":{"allOf":[{"$ref":"#/components/schemas/MessageStatusEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"Message delivery status changed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"message.status","messageId":"8f14e45f-ceea-467a-9575-4d2f7b0e2a31","status":"delivered","reason":null,"id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"CallRingingEvent":{"type":"object","properties":{"type":{"type":"string","enum":["call.ringing"]},"callId":{"type":"string"},"from":{"type":"string"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"devices":{"type":"array","items":{"type":"object","properties":{"deviceId":{"type":"string"},"userId":{"type":"string"}},"required":["deviceId","userId"]}}},"required":["type","callId","from","to","devices"],"description":"Softphone devices are being dialed. Fired per dialed softphone leg while an inbound call is ringing, so you can send a push notification that wakes a backgrounded app. Transient: it is attempted once and never retried, and the terminal `call.completed` / `call.missed` events remain the record. Never fired for SIP or PSTN-only routes.","example":{"type":"call.ringing","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","devices":[{"deviceId":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6","userId":"user_123"}]}},"CallRingingEventDelivery":{"allOf":[{"$ref":"#/components/schemas/CallRingingEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"Softphone devices are being dialed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"call.ringing","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","devices":[{"deviceId":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6","userId":"user_123"}],"id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"CallCompletedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["call.completed"]},"callId":{"type":"string"},"from":{"type":"string"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"answeredAt":{"type":["string","null"]},"endedAt":{"type":["string","null"]},"durationSeconds":{"type":["number","null"]},"answeredBy":{"type":["string","null"]},"answeredDevice":{"type":["object","null"],"properties":{"deviceId":{"type":"string"},"userId":{"type":"string"}},"required":["deviceId","userId"]},"direction":{"type":"string","enum":["inbound","outbound"]}},"required":["type","callId","from","to","answeredAt","endedAt","durationSeconds"],"description":"A call was answered and ended. Fired once when a call reaches its terminal state after being answered. `direction` is absent on older events; treat absence as `inbound`.","example":{"type":"call.completed","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","answeredAt":"2026-07-01T15:00:09.000Z","endedAt":"2026-07-01T15:03:30.000Z","durationSeconds":201,"answeredBy":"Front desk","direction":"inbound"}},"CallCompletedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/CallCompletedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A call was answered and ended, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"call.completed","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","answeredAt":"2026-07-01T15:00:09.000Z","endedAt":"2026-07-01T15:03:30.000Z","durationSeconds":201,"answeredBy":"Front desk","direction":"inbound","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"CallMissedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["call.missed"]},"callId":{"type":"string"},"from":{"type":"string"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"outcome":{"type":"string","enum":["missed","busy","failed","voicemail"]},"endedAt":{"type":["string","null"]},"direction":{"type":"string","enum":["inbound","outbound"]}},"required":["type","callId","from","to","outcome","endedAt"],"description":"A call ended without being answered. Fired when a call ends unanswered. `outcome` is `voicemail` when a machine picked up and nobody pressed 1. `direction` is absent on older events; treat absence as `inbound`.","example":{"type":"call.missed","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","outcome":"missed","endedAt":"2026-07-01T15:00:30.000Z","direction":"inbound"}},"CallMissedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/CallMissedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A call ended without being answered, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"call.missed","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","outcome":"missed","endedAt":"2026-07-01T15:00:30.000Z","direction":"inbound","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"CallIvrKeyPressedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["call.ivr.key_pressed"]},"callId":{"type":"string"},"numberId":{"type":"string"},"digit":{"type":"string"},"label":{"type":["string","null"]},"from":{"type":"string"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"at":{"type":"string"}},"required":["type","callId","numberId","digit","label","from","to","at"],"description":"A caller pressed an IVR menu key. Fired once per accepted keypress, before the key’s action runs. Invalid digits and timeouts never fire it.","example":{"type":"call.ivr.key_pressed","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","numberId":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d","digit":"1","label":"Sales","from":"+15555550142","to":"+15555550100","at":"2026-07-01T15:00:05.000Z"}},"CallIvrKeyPressedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/CallIvrKeyPressedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A caller pressed an IVR menu key, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"call.ivr.key_pressed","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","numberId":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d","digit":"1","label":"Sales","from":"+15555550142","to":"+15555550100","at":"2026-07-01T15:00:05.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"CallTranscriptEvent":{"type":"object","properties":{"type":{"type":"string","enum":["call.transcript"]},"callId":{"type":"string"},"recordingId":{"type":"string"},"from":{"type":"string"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"transcript":{"type":["string","null"]},"transcriptTurns":{"type":["array","null"],"items":{"type":"object","properties":{"speaker":{"type":"string","enum":["caller","rep"]},"text":{"type":"string"}},"required":["speaker","text"]}},"transcriptStatus":{"type":"string","enum":["available","failed"]},"durationSeconds":{"type":["number","null"]},"recordingUrl":{"type":"string"}},"required":["type","callId","recordingId","from","to","transcript","transcriptTurns","transcriptStatus","durationSeconds","recordingUrl"],"description":"A recorded call has been transcribed. Fired exactly once per recorded call, seconds to minutes after the call ends. A failed transcription still delivers, with `transcript: null` and `transcriptStatus: \"failed\"`.","example":{"type":"call.transcript","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","recordingId":"4a3b2c1d-0e9f-4a8b-8c7d-6e5f4a3b2c1d","from":"+15555550142","to":"+15555550100","transcript":"Thanks for calling Acme Plumbing...","transcriptTurns":[{"speaker":"rep","text":"Thanks for calling Acme Plumbing."}],"transcriptStatus":"available","durationSeconds":201,"recordingUrl":"/v1/calls/0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8/recording"}},"CallTranscriptEventDelivery":{"allOf":[{"$ref":"#/components/schemas/CallTranscriptEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A recorded call has been transcribed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"call.transcript","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","recordingId":"4a3b2c1d-0e9f-4a8b-8c7d-6e5f4a3b2c1d","from":"+15555550142","to":"+15555550100","transcript":"Thanks for calling Acme Plumbing...","transcriptTurns":[{"speaker":"rep","text":"Thanks for calling Acme Plumbing."}],"transcriptStatus":"available","durationSeconds":201,"recordingUrl":"/v1/calls/0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8/recording","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"CallTranscriptDeltaEvent":{"type":"object","properties":{"type":{"type":"string","enum":["call.transcript.delta"]},"callId":{"type":"string"},"speaker":{"type":"string","enum":["caller","rep"]},"text":{"type":"string"},"final":{"type":"boolean"},"at":{"type":"string"}},"required":["type","callId","speaker","text","final","at"],"description":"Live transcription of an in-progress call. Streamed while a call is bridged, only on routes with `liveTranscription` enabled. Best effort: delivered once, never retried, and not ordered, so sort a burst by `at`. Interim results (`final: false`) are superseded by the next result for the same speaker; only `final: true` results are stable turns. The terminal `call.transcript` remains the durable record.","example":{"type":"call.transcript.delta","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","speaker":"caller","text":"I have a leak under my sink","final":true,"at":"2026-07-01T15:00:20.000Z"}},"CallTranscriptDeltaEventDelivery":{"allOf":[{"$ref":"#/components/schemas/CallTranscriptDeltaEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"Live transcription of an in-progress call, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"call.transcript.delta","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","speaker":"caller","text":"I have a leak under my sink","final":true,"at":"2026-07-01T15:00:20.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"VoicemailReceivedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["voicemail.received"]},"callId":{"type":"string"},"voicemailId":{"type":"string"},"from":{"type":"string"},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"transcript":{"type":["string","null"]},"transcriptStatus":{"type":"string","enum":["available","failed"]},"durationSeconds":{"type":["number","null"]},"recordingUrl":{"type":"string"},"receivedAt":{"type":"string"}},"required":["type","callId","voicemailId","from","to","transcript","transcriptStatus","durationSeconds","recordingUrl","receivedAt"],"description":"A voicemail was captured and transcribed. Fired once per captured voicemail, seconds to minutes after the `call.missed` with outcome `voicemail`. A failed transcription still delivers with `transcript: null`; the audio remains available at `recordingUrl`.","example":{"type":"voicemail.received","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","voicemailId":"9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d","from":"+15555550142","to":"+15555550100","transcript":"Hi, this is Sam, calling about the leak under my sink.","transcriptStatus":"available","durationSeconds":24,"recordingUrl":"/v1/voicemails/9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d/audio","receivedAt":"2026-07-01T16:20:00.000Z"}},"VoicemailReceivedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/VoicemailReceivedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A voicemail was captured and transcribed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"voicemail.received","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","voicemailId":"9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d","from":"+15555550142","to":"+15555550100","transcript":"Hi, this is Sam, calling about the leak under my sink.","transcriptStatus":"available","durationSeconds":24,"recordingUrl":"/v1/voicemails/9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d/audio","receivedAt":"2026-07-01T16:20:00.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"WalletCreditedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["billing.wallet.credited"]},"kind":{"type":"string"},"amountCents":{"type":"number"},"balanceCents":{"type":"number"},"at":{"type":"string"}},"required":["type","kind","amountCents","balanceCents","at"],"description":"A wallet credit landed. Fired to the paying account when a top-up or auto-recharge lands.","example":{"type":"billing.wallet.credited","kind":"topup","amountCents":5000,"balanceCents":7250,"at":"2026-07-01T12:00:00.000Z"}},"WalletCreditedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/WalletCreditedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A wallet credit landed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"billing.wallet.credited","kind":"topup","amountCents":5000,"balanceCents":7250,"at":"2026-07-01T12:00:00.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"WalletLowBalanceEvent":{"type":"object","properties":{"type":{"type":"string","enum":["billing.wallet.low_balance"]},"balanceCents":{"type":"number"},"thresholdCents":{"type":"number"},"autoRechargeStarted":{"type":"boolean"},"at":{"type":"string"}},"required":["type","balanceCents","thresholdCents","autoRechargeStarted","at"],"description":"The wallet dropped below the recharge threshold. Fired once per threshold crossing. `autoRechargeStarted` is false when there is no saved card or auto-recharge is disabled.","example":{"type":"billing.wallet.low_balance","balanceCents":450,"thresholdCents":1000,"autoRechargeStarted":true,"at":"2026-07-01T12:00:00.000Z"}},"WalletLowBalanceEventDelivery":{"allOf":[{"$ref":"#/components/schemas/WalletLowBalanceEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"The wallet dropped below the recharge threshold, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"billing.wallet.low_balance","balanceCents":450,"thresholdCents":1000,"autoRechargeStarted":true,"at":"2026-07-01T12:00:00.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"SubscriptionUpdatedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["billing.subscription.updated"]},"status":{"type":"string"},"currentPeriodEnd":{"type":["string","null"]},"at":{"type":"string"}},"required":["type","status","currentPeriodEnd","at"],"description":"The subscription status changed. Fired when the subscription status changes (`active`, `past_due`, `canceled`, ...).","example":{"type":"billing.subscription.updated","status":"active","currentPeriodEnd":"2026-08-01T00:00:00.000Z","at":"2026-07-01T12:00:00.000Z"}},"SubscriptionUpdatedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/SubscriptionUpdatedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"The subscription status changed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"billing.subscription.updated","status":"active","currentPeriodEnd":"2026-08-01T00:00:00.000Z","at":"2026-07-01T12:00:00.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"LeadCapturedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["lead.captured"]},"leadId":{"type":"string"},"brandId":{"type":"string"},"firstName":{"type":["string","null"]},"lastName":{"type":["string","null"]},"email":{"type":["string","null"]},"phone":{"type":["string","null"]},"consent":{"type":"boolean"},"consentText":{"type":["string","null"]},"capturedAt":{"type":"string"}},"required":["type","leadId","brandId","firstName","lastName","email","phone","consent","consentText","capturedAt"],"description":"A brand’s hosted opt-in page was submitted. Carries the captured lead so you can route it into your own CRM or automation. `consent` reflects the SMS-consent checkbox and `consentText` is the exact language shown, for your audit trail.","example":{"type":"lead.captured","leadId":"e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b","brandId":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718","firstName":"Sam","lastName":"Rivera","email":"sam@example.com","phone":"+15555550142","consent":true,"consentText":"I agree to receive text messages from Acme Plumbing.","capturedAt":"2026-07-01T11:45:00.000Z"}},"LeadCapturedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/LeadCapturedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A brand’s hosted opt-in page was submitted, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"lead.captured","leadId":"e5f6a7b8-c9d0-4e1f-8a2b-3c4d5e6f7a8b","brandId":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718","firstName":"Sam","lastName":"Rivera","email":"sam@example.com","phone":"+15555550142","consent":true,"consentText":"I agree to receive text messages from Acme Plumbing.","capturedAt":"2026-07-01T11:45:00.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"WebhookEndpointDisabledEvent":{"type":"object","properties":{"type":{"type":"string","enum":["webhook_endpoint.disabled"]},"endpointId":{"type":"string"},"url":{"type":"string"},"reason":{"type":"string","enum":["consecutive_failures"]},"consecutiveFailures":{"type":"integer","minimum":0},"disabledAt":{"type":"string"}},"required":["type","endpointId","url","reason","consecutiveFailures","disabledAt"],"description":"A webhook endpoint was automatically disabled. Fired when an endpoint is disabled after sustained failure (at least 50 consecutive failed attempts, no success in 72 hours, and a failing streak at least 72 hours old). It is delivered to your other enabled endpoints that subscribe to it and appears in `GET /v1/events`, never to the disabled endpoint itself. Re-enable with `PATCH /v1/webhooks/{id}` and `{\"enabled\": true}`.","example":{"type":"webhook_endpoint.disabled","endpointId":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d","url":"https://example.com/webhooks/mittis","reason":"consecutive_failures","consecutiveFailures":212,"disabledAt":"2026-07-04T09:30:00.000Z"}},"WebhookEndpointDisabledEventDelivery":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpointDisabledEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A webhook endpoint was automatically disabled, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"webhook_endpoint.disabled","endpointId":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d","url":"https://example.com/webhooks/mittis","reason":"consecutive_failures","consecutiveFailures":212,"disabledAt":"2026-07-04T09:30:00.000Z","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"DomainVerifiedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["domain.verified"]},"domainId":{"type":"string"},"domain":{"type":"string"},"status":{"type":"string","enum":["pending","verified","failed","degraded","suspended"]}},"required":["type","domainId","domain","status"],"description":"A sending domain was verified. Fired once when a sending domain becomes `verified` (including recovering from `degraded`). It can send from now on. Fetch it with `GET /v1/domains/{domainId}`.","example":{"type":"domain.verified","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"verified"}},"DomainVerifiedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/DomainVerifiedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A sending domain was verified, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"domain.verified","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"verified","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"DomainFailedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["domain.failed"]},"domainId":{"type":"string"},"domain":{"type":"string"},"status":{"type":"string","enum":["pending","verified","failed","degraded","suspended"]}},"required":["type","domainId","domain","status"],"description":"A sending domain failed verification. Fired when a required DNS record is missing or wrong and the domain moves to `failed`. Fix the records and call `POST /v1/domains/{domainId}/verify`.","example":{"type":"domain.failed","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"failed"}},"DomainFailedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/DomainFailedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A sending domain failed verification, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"domain.failed","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"failed","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"DomainDegradedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["domain.degraded"]},"domainId":{"type":"string"},"domain":{"type":"string"},"status":{"type":"string","enum":["pending","verified","failed","degraded","suspended"]}},"required":["type","domainId","domain","status"],"description":"A verified sending domain degraded. Fired when a previously verified domain has a required record that now fails. It cannot send until you fix DNS; it returns to `verified` automatically once the records recover.","example":{"type":"domain.degraded","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"degraded"}},"DomainDegradedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/DomainDegradedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A verified sending domain degraded, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"domain.degraded","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"degraded","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"DomainExpiredEvent":{"type":"object","properties":{"type":{"type":"string","enum":["domain.expired"]},"domainId":{"type":"string"},"domain":{"type":"string"},"status":{"type":"string","enum":["expired"]}},"required":["type","domainId","domain","status"],"description":"An unverified sending domain was released. Fired when a domain that was never verified is released after 7 days. The domain no longer exists on your account; add it again to retry. Domains that were ever verified are never released automatically.","example":{"type":"domain.expired","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"expired"}},"DomainExpiredEventDelivery":{"allOf":[{"$ref":"#/components/schemas/DomainExpiredEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"An unverified sending domain was released, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"type":"domain.expired","domainId":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"expired","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailSentEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.sent"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"An email left our servers for a recipient. Fired per recipient when the email has been handed to the recipient's mail server queue. Every `email.*` event is per recipient: an email to three people fires up to three of each. `recipient` is omitted for a bcc recipient we cannot tell apart from the email's other bcc recipients.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.sent","status":"sent"}},"EmailSentEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailSentEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"An email left our servers for a recipient, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.sent","status":"sent","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailDeliveredEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.delivered"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"An email was delivered to a recipient. Fired per recipient when the recipient's mail server accepted the message.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.delivered","status":"delivered"}},"EmailDeliveredEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailDeliveredEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"An email was delivered to a recipient, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.delivered","status":"delivered","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailDeferredEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.deferred"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"Delivery to a recipient was delayed. Fired when the recipient's server temporarily refused the message. We keep retrying; a later `email.delivered` or `email.bounced` settles it.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.deferred","status":"deferred"}},"EmailDeferredEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailDeferredEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"Delivery to a recipient was delayed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.deferred","status":"deferred","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailBouncedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.bounced"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"An email bounced for a recipient. Fired when delivery to a recipient permanently failed. `bounce.class` is `hard` (the address does not exist; the address is added to your suppression list), `soft`, `administrative`, `expired` or `unknown`.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.bounced","status":"bounced","bounce":{"class":"hard","code":30001,"message":"Mailbox does not exist"}}},"EmailBouncedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailBouncedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"An email bounced for a recipient, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.bounced","status":"bounced","bounce":{"class":"hard","code":30001,"message":"Mailbox does not exist"},"id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailFailedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.failed"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"An email failed for a recipient. Fired when a message could not be sent to a recipient for a reason other than a bounce.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.failed","status":"failed","bounce":{"class":"unknown","code":null,"message":null}}},"EmailFailedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailFailedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"An email failed for a recipient, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.failed","status":"failed","bounce":{"class":"unknown","code":null,"message":null},"id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailOpenedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.opened"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"A recipient opened an email. Fired when a recipient opens the email. Only sent when open tracking is enabled for your account; opens are not fully reliable (mail apps can pre-load images).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.opened","status":"delivered"}},"EmailOpenedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailOpenedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A recipient opened an email, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.opened","status":"delivered","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailClickedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.clicked"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"A recipient clicked a link. Fired when a recipient clicks a tracked link; `url` is the link. Only sent when click tracking is enabled for your account.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.clicked","status":"delivered","url":"https://example.com/estimate/1042"}},"EmailClickedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailClickedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A recipient clicked a link, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.clicked","status":"delivered","url":"https://example.com/estimate/1042","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailComplainedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.complained"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"A recipient reported the email as spam. Fired when a recipient marks the email as spam. The address is added to your suppression list and cannot be removed. Complaint rates above 0.2% pause your email sending.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.complained","status":"complained"}},"EmailComplainedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailComplainedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A recipient reported the email as spam, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.complained","status":"complained","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"EmailUnsubscribedEvent":{"type":"object","properties":{"type":{"type":"string","enum":["email.unsubscribed"]},"emailId":{"type":"string"},"recipient":{"type":"string"},"recipientKind":{"type":"string","enum":["to","cc","bcc"]},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"]},"occurredAt":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"]},"url":{"type":"string"},"method":{"type":"string"}},"required":["type","emailId","recipientKind","status","occurredAt","tags","metadata","externalRef"],"description":"A recipient unsubscribed. Fired when a recipient unsubscribes (`method` is `link` or `one_click`). The address is added to your suppression list; you can remove it if they opt back in.","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.unsubscribed","status":"delivered","method":"one_click"}},"EmailUnsubscribedEventDelivery":{"allOf":[{"$ref":"#/components/schemas/EmailUnsubscribedEvent"},{"type":"object","properties":{"id":{"type":"string","description":"Event id (`evt_…`). Stable across retries and identical to the `eventId` in `GET /v1/events`: dedupe on it, because delivery is at-least-once."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601), not when this attempt was sent."}},"required":["id","createdAt"]}],"description":"A recipient unsubscribed, exactly as delivered to your endpoint (the event plus `id` and `createdAt`).","example":{"emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","recipient":"dana@example.com","recipientKind":"to","occurredAt":"2026-07-01T15:04:09.000Z","tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"type":"email.unsubscribed","status":"delivered","method":"one_click","id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","createdAt":"2026-07-01T15:09:42.000Z"}},"WebhookEventPayload":{"oneOf":[{"$ref":"#/components/schemas/MessageReceivedEvent"},{"$ref":"#/components/schemas/MessageStatusEvent"},{"$ref":"#/components/schemas/CallRingingEvent"},{"$ref":"#/components/schemas/CallCompletedEvent"},{"$ref":"#/components/schemas/CallMissedEvent"},{"$ref":"#/components/schemas/CallIvrKeyPressedEvent"},{"$ref":"#/components/schemas/CallTranscriptEvent"},{"$ref":"#/components/schemas/CallTranscriptDeltaEvent"},{"$ref":"#/components/schemas/VoicemailReceivedEvent"},{"$ref":"#/components/schemas/WalletCreditedEvent"},{"$ref":"#/components/schemas/WalletLowBalanceEvent"},{"$ref":"#/components/schemas/SubscriptionUpdatedEvent"},{"$ref":"#/components/schemas/LeadCapturedEvent"},{"$ref":"#/components/schemas/WebhookEndpointDisabledEvent"},{"$ref":"#/components/schemas/DomainVerifiedEvent"},{"$ref":"#/components/schemas/DomainFailedEvent"},{"$ref":"#/components/schemas/DomainDegradedEvent"},{"$ref":"#/components/schemas/DomainExpiredEvent"},{"$ref":"#/components/schemas/EmailSentEvent"},{"$ref":"#/components/schemas/EmailDeliveredEvent"},{"$ref":"#/components/schemas/EmailDeferredEvent"},{"$ref":"#/components/schemas/EmailBouncedEvent"},{"$ref":"#/components/schemas/EmailFailedEvent"},{"$ref":"#/components/schemas/EmailOpenedEvent"},{"$ref":"#/components/schemas/EmailClickedEvent"},{"$ref":"#/components/schemas/EmailComplainedEvent"},{"$ref":"#/components/schemas/EmailUnsubscribedEvent"}],"discriminator":{"propertyName":"type","mapping":{"message.received":"#/components/schemas/MessageReceivedEvent","message.status":"#/components/schemas/MessageStatusEvent","call.ringing":"#/components/schemas/CallRingingEvent","call.completed":"#/components/schemas/CallCompletedEvent","call.missed":"#/components/schemas/CallMissedEvent","call.ivr.key_pressed":"#/components/schemas/CallIvrKeyPressedEvent","call.transcript":"#/components/schemas/CallTranscriptEvent","call.transcript.delta":"#/components/schemas/CallTranscriptDeltaEvent","voicemail.received":"#/components/schemas/VoicemailReceivedEvent","billing.wallet.credited":"#/components/schemas/WalletCreditedEvent","billing.wallet.low_balance":"#/components/schemas/WalletLowBalanceEvent","billing.subscription.updated":"#/components/schemas/SubscriptionUpdatedEvent","lead.captured":"#/components/schemas/LeadCapturedEvent","webhook_endpoint.disabled":"#/components/schemas/WebhookEndpointDisabledEvent","domain.verified":"#/components/schemas/DomainVerifiedEvent","domain.failed":"#/components/schemas/DomainFailedEvent","domain.degraded":"#/components/schemas/DomainDegradedEvent","domain.expired":"#/components/schemas/DomainExpiredEvent","email.sent":"#/components/schemas/EmailSentEvent","email.delivered":"#/components/schemas/EmailDeliveredEvent","email.deferred":"#/components/schemas/EmailDeferredEvent","email.bounced":"#/components/schemas/EmailBouncedEvent","email.failed":"#/components/schemas/EmailFailedEvent","email.opened":"#/components/schemas/EmailOpenedEvent","email.clicked":"#/components/schemas/EmailClickedEvent","email.complained":"#/components/schemas/EmailComplainedEvent","email.unsubscribed":"#/components/schemas/EmailUnsubscribedEvent"}},"description":"Any event body, discriminated on `type`. This is the `payload` of an event-feed record and, with `id` and `createdAt` added, the body POSTed to webhook endpoints."},"TenantEvent":{"type":"object","properties":{"id":{"type":"string","description":"Feed row id (uuid). Use it as the `after` cursor."},"eventId":{"type":"string","description":"The wire event id (`evt_…`) that delivered webhooks carry as `id`. Dedupe across both lanes on this."},"type":{"type":"string","description":"The event type, e.g. `message.received`."},"createdAt":{"type":"string","description":"When the event was recorded (ISO 8601)."},"payload":{"$ref":"#/components/schemas/WebhookEventPayload"}},"required":["id","eventId","type","createdAt","payload"],"description":"One durable record of an event, as returned by the polling feed.","example":{"id":"6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","eventId":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","type":"message.received","createdAt":"2026-07-01T15:09:42.000Z","payload":{"type":"message.received","messageId":"8f14e45f-ceea-467a-9575-4d2f7b0e2a31","from":"+15555550142","to":"+15555550100","body":"Yes, Tuesday works!","receivedAt":"2026-07-01T15:09:41.000Z","providerMessageId":"msg_5f8e2c1a"}}},"TenantEventFeedPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TenantEvent"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"TenantEventFeed":{"allOf":[{"$ref":"#/components/schemas/TenantEventFeedPage"},{"type":"object","properties":{"cursor":{"type":["string","null"],"description":"The id to pass as `after` on the next poll (`order=asc`) or as `before` for the next older page (`order=desc`): the last event returned, or the id you passed when nothing is new. With `after=now` it is the newest event id (null if there are none)."}},"required":["cursor"]}],"description":"Events oldest to newest (default) or newest to oldest with `order=desc`. With `order=asc` a full page means more may follow: `nextCursor` equals `cursor` in that case and is null otherwise. With `order=desc`, `hasMore` is exact and `nextCursor` (pass it as `before`) is null on the last page."},"WebhookEndpoint":{"type":"object","properties":{"id":{"type":"string","description":"Endpoint id."},"url":{"type":"string","description":"Where events are POSTed."},"events":{"type":["array","null"],"items":{"type":"string"},"description":"Subscribed event types; null means every event."},"enabled":{"type":"boolean","description":"Disabled endpoints receive nothing. Set `true` via PATCH to re-enable (also resets the failure counters)."},"disabledAt":{"type":["string","null"],"description":"ISO 8601. Set when the endpoint was auto-disabled for sustained failure; else null."},"disabledReason":{"type":["string","null"],"description":"Why it was auto-disabled (`consecutive_failures`); else null."},"consecutiveFailures":{"type":"integer","minimum":0,"description":"Failed delivery attempts in a row since the last success."},"lastSuccessAt":{"type":["string","null"],"description":"ISO 8601. Last 2xx from your receiver; null if never."},"createdAt":{"type":"string","description":"ISO 8601."}},"required":["id","url","events","enabled","disabledAt","disabledReason","consecutiveFailures","lastSuccessAt","createdAt"],"description":"A configured webhook endpoint. The signing secret is write-once and never listed.","example":{"id":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d","url":"https://example.com/webhooks/mittis","events":["message.received","message.status"],"enabled":true,"disabledAt":null,"disabledReason":null,"consecutiveFailures":0,"lastSuccessAt":"2026-06-02T08:15:00.000Z","createdAt":"2026-06-01T12:00:00.000Z"}},"WebhookEndpointPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookEndpoint"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"WebhookEndpointCreated":{"allOf":[{"$ref":"#/components/schemas/WebhookEndpoint"},{"type":"object","properties":{"secret":{"type":"string","description":"The signing secret (`whsec_…`). Returned only now; store it. Use it to verify the `X-Mittis-Signature` header."}},"required":["secret"]}],"description":"A webhook endpoint with its one-time signing secret, returned when you create the endpoint or rotate its secret.","example":{"id":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d","url":"https://example.com/webhooks/mittis","events":null,"enabled":true,"createdAt":"2026-06-01T12:00:00.000Z","secret":"whsec_3f0c9a8b7d6e5f4a3b2c1d0e9f8a7b6c"}},"WebhookDelivery":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id."},"eventId":{"type":"string","description":"The event id (`evt_…`) being delivered."},"eventType":{"type":"string","description":"The event type."},"status":{"type":"string","enum":["pending","failed","succeeded","abandoned"],"description":"`pending` (first attempt in flight or scheduled), `failed` (a retry is scheduled), `succeeded`, or `abandoned` (out of attempts, or the receiver permanently rejected it)."},"attempts":{"type":"integer","minimum":0,"description":"Attempts made so far."},"nextAttemptAt":{"type":["string","null"],"description":"When the next retry is scheduled, if any (ISO 8601)."},"lastStatusCode":{"type":["integer","null"],"description":"HTTP status of the last attempt; null when there was no response."},"lastError":{"type":["string","null"],"description":"A short code for the last failure: `timeout`, `connection_failed` or `http_<status>`."},"lastAttemptAt":{"type":["string","null"],"description":"ISO 8601."},"deliveredAt":{"type":["string","null"],"description":"When it succeeded (ISO 8601)."},"createdAt":{"type":"string","description":"ISO 8601."}},"required":["id","eventId","eventType","status","attempts","nextAttemptAt","lastStatusCode","lastError","lastAttemptAt","deliveredAt","createdAt"],"description":"One (event, endpoint) delivery. The list carries no event payload; retrieve a single delivery for the body that is sent.","example":{"id":"f0e1d2c3-b4a5-4968-8776-655443322110","eventId":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","eventType":"message.received","status":"succeeded","attempts":1,"nextAttemptAt":null,"lastStatusCode":200,"lastError":null,"lastAttemptAt":"2026-07-01T15:09:43.000Z","deliveredAt":"2026-07-01T15:09:43.000Z","createdAt":"2026-07-01T15:09:42.000Z"}},"WebhookDeliveryDetail":{"type":"object","properties":{"id":{"type":"string","description":"Delivery id."},"eventId":{"type":"string","description":"The event id (`evt_…`) being delivered."},"eventType":{"type":"string","description":"The event type."},"status":{"type":"string","enum":["pending","failed","succeeded","abandoned"],"description":"Same values as on the list."},"attempts":{"type":"integer","minimum":0,"description":"Attempts made so far."},"nextAttemptAt":{"type":["string","null"],"description":"When the next retry is scheduled, if any (ISO 8601)."},"lastStatusCode":{"type":["integer","null"],"description":"HTTP status of the last attempt; null when there was no response."},"lastError":{"type":["string","null"],"description":"A short code for the last failure: `timeout`, `connection_failed` or `http_<status>`."},"lastAttemptAt":{"type":["string","null"],"description":"ISO 8601."},"deliveredAt":{"type":["string","null"],"description":"When it succeeded (ISO 8601)."},"createdAt":{"type":"string","description":"ISO 8601."},"payload":{"type":"object","additionalProperties":{},"description":"The event body that is sent (and re-sent on every retry): the same envelope your receiver gets, including `id`. JSON key order may differ from the wire body, so verify signatures against the raw request, not this."}},"required":["id","eventId","eventType","status","attempts","nextAttemptAt","lastStatusCode","lastError","lastAttemptAt","deliveredAt","createdAt","payload"],"description":"A webhook delivery together with the event body it sends.","example":{"id":"f0e1d2c3-b4a5-4968-8776-655443322110","eventId":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","eventType":"message.received","status":"succeeded","attempts":1,"nextAttemptAt":null,"lastStatusCode":200,"lastError":null,"lastAttemptAt":"2026-07-01T15:09:43.000Z","deliveredAt":"2026-07-01T15:09:43.000Z","createdAt":"2026-07-01T15:09:42.000Z","payload":{"id":"evt_6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b","type":"message.received"}}},"WebhookDeliveryPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WebhookDelivery"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"RoutingDecisionRequest":{"type":"object","properties":{"numberId":{"type":"string","description":"The number being called."},"callId":{"type":"string","description":"The call id."},"from":{"type":"string","description":"Caller id as reported by the carrier."},"to":{"type":"string","description":"The number that was called (E.164)."},"startedAt":{"type":"string","description":"When the call started (ISO 8601)."}},"required":["numberId","callId","from","to","startedAt"],"description":"Sent to a number’s `decisionWebhook.url` as an inbound call opens.","example":{"numberId":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d","callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550142","to":"+15555550100","startedAt":"2026-07-01T15:00:00.000Z"}},"RoutingDecisionResponse":{"oneOf":[{"type":"object","properties":{"decision":{"type":"string","enum":["default"]}},"required":["decision"]},{"type":"object","properties":{"decision":{"type":"string","enum":["override"]},"ring":{"type":"object","properties":{"ringMode":{"type":"string","enum":["simultaneous","sequential","staged"],"default":"simultaneous"},"destinations":{"type":"array","items":{"type":"object","properties":{"destinationType":{"type":"string","enum":["sip","pstn","webrtc"]},"destination":{"type":"string","minLength":3,"maxLength":200},"label":{"type":"string","minLength":1,"maxLength":80},"stage":{"type":"integer","minimum":0,"maximum":4,"default":0},"ringTimeoutSecs":{"type":"integer","minimum":5,"maximum":120,"default":25},"enabled":{"type":"boolean","default":true}},"required":["destinationType","destination"]},"minItems":1,"maxItems":10},"noAnswerAction":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["voicemail"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["forward"]},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},"required":["type","to"]}]}},"required":["destinations"]}},"required":["decision","ring"]}],"description":"`{ \"decision\": \"default\" }` runs the number’s configured route. `{ \"decision\": \"override\", \"ring\": { ... } }` replaces the ring plan for this call only."},"ApiKey":{"type":"object","properties":{"id":{"type":"string","description":"Key id."},"name":{"type":"string","description":"The label you gave the key."},"mode":{"type":"string","enum":["live","test"],"description":"`live` keys send for real; `test` keys are stubbed and never reach a carrier."},"displayHint":{"type":"string","description":"A masked form of the key for display, e.g. `sk_live_••••a1b2`. The secret is never shown again."},"createdAt":{"type":"string","description":"ISO 8601."},"lastUsedAt":{"type":["string","null"],"description":"When the key was last used (ISO 8601); null if never."},"revokedAt":{"type":["string","null"],"description":"When it was revoked (ISO 8601); null while active."}},"required":["id","name","mode","displayHint","createdAt","lastUsedAt","revokedAt"],"description":"An API key. The secret and its hash are never returned.","example":{"id":"6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d","name":"Production server","mode":"live","displayHint":"sk_live_••••a1b2","createdAt":"2026-06-01T12:00:00.000Z","lastUsedAt":"2026-07-01T15:00:00.000Z","revokedAt":null}},"ApiKeyPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"ApiKeyCreated":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"mode":{"type":"string","enum":["live","test"]},"displayHint":{"type":"string"},"secret":{"type":"string","description":"The full key (`sk_live_…` / `sk_test_…`). Returned exactly once and never stored; save it now."}},"required":["id","name","mode","displayHint","secret"],"description":"A newly created API key including its one-time secret.","example":{"id":"6a5b4c3d-2e1f-4a0b-9c8d-7e6f5a4b3c2d","name":"Production server","mode":"live","displayHint":"sk_live_••••a1b2","secret":"sk_live_EXAMPLEEXAMPLEEXAMPLEEXAMPLEEXAMPLE"}},"Usage":{"type":"object","properties":{"period":{"type":"string","description":"The billing period, `YYYY-MM`."},"messages":{"type":"number","description":"Messages sent this period."},"segments":{"type":"number","description":"Billable SMS segments this period."},"priceCents":{"type":"number","description":"What you have been billed for usage this period, in cents."},"emailRecipients":{"type":"number","description":"Email recipients (to, cc and bcc) accepted for delivery this period."},"costCents":{"type":"number","description":"Deprecated: an alias of `priceCents` with the same value. Use `priceCents`.","deprecated":true},"budget":{"type":["object","null"],"properties":{"monthlyLimitCents":{"type":["number","null"]},"periodSpentCents":{"type":"number"},"softThresholdPct":{"type":"number"}},"required":["monthlyLimitCents","periodSpentCents","softThresholdPct"],"description":"Your monthly spend limit and progress against it; null when no limit is set."}},"required":["period","messages","segments","priceCents","emailRecipients","costCents","budget"],"description":"Meters and spend for the current billing period.","example":{"period":"2026-07","messages":1240,"segments":1411,"emailRecipients":3200,"priceCents":1594,"costCents":1594,"budget":{"monthlyLimitCents":20000,"periodSpentCents":1594,"softThresholdPct":80}}},"Billing":{"type":"object","properties":{"plan":{"type":"string","description":"Your pricing tier: `single`, `agency` or `subaccount`."},"planFeeCents":{"type":"number","description":"What you are actually billed monthly, in cents. Zero for a legacy plan that is not billed."},"planListPriceCents":{"type":"number","description":"The list price of your tier in cents, i.e. what a subscribe checkout would charge."},"subscription":{"type":"object","properties":{"status":{"type":"string"},"currentPeriodEnd":{"type":["string","null"]},"priceCents":{"type":"number"}},"required":["status","currentPeriodEnd","priceCents"]},"wallet":{"type":"object","properties":{"enabled":{"type":"boolean"},"balanceCents":{"type":"number"},"autoRecharge":{"type":"object","properties":{"enabled":{"type":"boolean"},"thresholdCents":{"type":"number"},"amountCents":{"type":"number"}},"required":["enabled","thresholdCents","amountCents"]},"hasSavedPaymentMethod":{"type":"boolean"}},"required":["enabled","balanceCents","autoRecharge","hasSavedPaymentMethod"]},"stripeConfigured":{"type":"boolean","description":"Whether card payments are configured on this deployment (otherwise checkout and portal sessions fail)."}},"required":["plan","planFeeCents","planListPriceCents","subscription","wallet","stripeConfigured"],"description":"Subscription and prepaid-wallet snapshot. All money is integer cents.","example":{"plan":"single","planFeeCents":5000,"planListPriceCents":5000,"subscription":{"status":"active","currentPeriodEnd":"2026-08-01T00:00:00.000Z","priceCents":5000},"wallet":{"enabled":true,"balanceCents":7250,"autoRecharge":{"enabled":true,"thresholdCents":1000,"amountCents":5000},"hasSavedPaymentMethod":true},"stripeConfigured":true}},"CheckoutSession":{"type":"object","properties":{"url":{"type":"string","description":"The hosted page to send the user to. Short-lived."}},"required":["url"],"description":"A hosted checkout or billing-portal session.","example":{"url":"https://billing.example.com/session/cs_example"}},"WalletTransaction":{"type":"object","properties":{"id":{"type":"string","description":"Ledger row id."},"kind":{"type":"string","description":"`topup`, `auto_recharge`, `usage`, `number_rental`, `agent_fee` or `adjustment`."},"amountCents":{"type":"number","description":"Signed: positive is a credit, negative a debit."},"balanceAfterCents":{"type":"number","description":"The balance after this row."},"description":{"type":"string","description":"A short description of the charge or credit."},"createdAt":{"type":"string","description":"ISO 8601."}},"required":["id","kind","amountCents","balanceAfterCents","description","createdAt"],"description":"One row of the prepaid wallet ledger.","example":{"id":"b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e","kind":"topup","amountCents":5000,"balanceAfterCents":7250,"description":"Wallet top-up","createdAt":"2026-07-01T12:00:00.000Z"}},"WalletTransactionPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/WalletTransaction"}}},"required":["data"]}],"description":"A page of ledger rows, newest first. Pass `nextCursor` back as `cursor` (or the legacy `after`)."},"AgencyUsageRollup":{"type":"object","properties":{"period":{"type":"string","description":"`YYYY-MM`."},"agency":{"type":"object","additionalProperties":{"type":"number"},"description":"The agency account’s own meters."},"subaccounts":{"type":"array","items":{"type":"object","properties":{"tenantId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"meters":{"type":"object","additionalProperties":{"type":"number"},"description":"Usage meters for the period, keyed by meter name (`messages`, `segments`, `price_cents`, `voice_minutes`, `recording_minutes`, `transcription_minutes`, …)."}},"required":["tenantId","slug","name","meters"]}},"totals":{"type":"object","additionalProperties":{"type":"number"},"description":"Every meter summed across the agency and all sub-accounts."}},"required":["period","agency","subaccounts","totals"],"description":"Usage across the agency and every sub-account for one period.","example":{"period":"2026-07","agency":{"messages":10,"segments":10,"price_cents":11},"subaccounts":[{"tenantId":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11","slug":"acme-plumbing","name":"Acme Plumbing","meters":{"messages":1240,"segments":1411,"price_cents":1594}}],"totals":{"messages":1250,"segments":1421,"price_cents":1605}}},"AgencyStatement":{"type":"object","properties":{"period":{"type":"string","description":"`YYYY-MM`."},"plan":{"type":"string"},"planFeeCents":{"type":"number","description":"The list monthly fee of the agency plan, in cents."},"agency":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","description":"e.g. `platform`, `usage`."},"description":{"type":"string"},"cents":{"type":"number"}},"required":["category","description","cents"]},"description":"The agency’s own line items."},"totalCents":{"type":"number"}},"required":["items","totalCents"]},"subaccounts":{"type":"array","items":{"type":"object","properties":{"tenantId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"items":{"type":"array","items":{"type":"object","properties":{"category":{"type":"string","description":"e.g. `platform`, `usage`."},"description":{"type":"string"},"cents":{"type":"number"}},"required":["category","description","cents"]}},"totalCents":{"type":"number"}},"required":["tenantId","slug","name","items","totalCents"]},"description":"Each sub-account’s line items."},"usage":{"type":"object","properties":{"period":{"type":"string"},"totals":{"type":"object","additionalProperties":{"type":"number"},"description":"Usage meters for the period, keyed by meter name (`messages`, `segments`, `price_cents`, `voice_minutes`, `recording_minutes`, `transcription_minutes`, …)."},"agency":{"type":"object","properties":{"meters":{"type":"object","additionalProperties":{"type":"number"},"description":"Usage meters for the period, keyed by meter name (`messages`, `segments`, `price_cents`, `voice_minutes`, `recording_minutes`, `transcription_minutes`, …)."},"usageCents":{"type":"number","description":"Live-priced usage so far this period, in cents."}},"required":["meters","usageCents"]},"subaccounts":{"type":"array","items":{"type":"object","properties":{"tenantId":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"meters":{"type":"object","additionalProperties":{"type":"number"},"description":"Usage meters for the period, keyed by meter name (`messages`, `segments`, `price_cents`, `voice_minutes`, `recording_minutes`, `transcription_minutes`, …)."},"usageCents":{"type":"number"}},"required":["tenantId","slug","name","meters","usageCents"]}}},"required":["period","totals","agency","subaccounts"],"description":"Usage meters with live pricing."},"unbilledUsageCents":{"type":"number","description":"Usage in the open period that has not been invoiced yet, in cents."},"totalCents":{"type":"number","description":"Own items + sub-account items + unbilled usage, in cents."},"wallet":{"type":"object","properties":{"enabled":{"type":"boolean"},"balanceCents":{"type":"number"}},"required":["enabled","balanceCents"]},"subscription":{"type":"object","properties":{"status":{"type":"string"},"currentPeriodEnd":{"type":["string","null"]}},"required":["status","currentPeriodEnd"]}},"required":["period","plan","planFeeCents","agency","subaccounts","usage","unbilledUsageCents","totalCents","wallet","subscription"],"description":"The agency statement for one period: its own fee and line items, every sub-account’s items and usage, aggregated at read time."},"WalletReconciliation":{"type":"object","properties":{"report":{"type":["object","null"],"properties":{"currency":{"type":"string","enum":["USD"]},"checkedAt":{"type":"string","description":"ISO 8601."},"period":{"type":"string","description":"`YYYY-MM`."},"balanceUsd":{"type":"number","description":"Current wallet balance in dollars."},"ledgerUsd":{"type":"number","description":"Balance implied by the ledger, in dollars."},"differenceUsd":{"type":"number","description":"Balance minus ledger; zero when they agree."},"unmatchedCharges":{"type":"integer"},"pendingPayments":{"type":"integer"},"unverifiedPayments":{"type":"integer"},"mismatchedPayments":{"type":"integer"},"status":{"type":"string","enum":["matched","unverified","needs_review"]},"payments":{"type":"array","items":{"type":"object","properties":{"reference":{"type":"string"},"amountUsd":{"type":"number"},"status":{"type":"string","enum":["matched","needs_review","unverified"]}},"required":["reference","amountUsd","status"]}},"note":{"type":"string"}},"required":["currency","checkedAt","period","balanceUsd","ledgerUsd","differenceUsd","unmatchedCharges","pendingPayments","unverifiedPayments","mismatchedPayments","status","payments","note"],"description":"Null when the account has no wallet."}},"required":["report"],"description":"A read-only check that the wallet balance agrees with its ledger and recorded payments. Nothing is changed. Amounts here are in dollars, unlike the rest of the API."},"AgencyNumber":{"type":"object","properties":{"id":{"type":"string","description":"Number id."},"phoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number (E.164)."},"status":{"type":"string","description":"Number status."},"type":{"type":"string","enum":["local","tollfree"],"description":"`local` or `tollfree`."},"capabilities":{"type":"object","properties":{"sms":{"type":"boolean"},"mms":{"type":"boolean"},"voice":{"type":"boolean"}},"required":["sms","mms","voice"]},"tenant":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string"}},"required":["id","slug","name","kind"],"description":"The owning account. `kind` is `agency` for the agency’s own numbers, else `subaccount`."},"rentalCents":{"type":"number","description":"The monthly rental billed to the owner, in cents."},"routeSummary":{"type":["string","null"],"description":"A one-line routing summary (\"→ +1804…\", \"rings 3 phones\", \"unrouted\"), or null."}},"required":["id","phoneNumber","status","type","capabilities","tenant","rentalCents","routeSummary"],"description":"One number in the agency fleet."},"AgencyNumberPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/AgencyNumber"}}},"required":["data"]}],"description":"Every number across the agency and its sub-accounts."},"Port":{"type":"object","properties":{"id":{"type":"string","description":"Port request id."},"phoneNumber":{"type":"string","description":"The first number on the request (E.164). All numbers are in `numbers` on the detail."},"status":{"type":"string","enum":["draft","pending_validation","validation_failed","submitted","foc_confirmed","porting","completed","rejected","cancel_requested","cancelled"],"description":"`draft` (created, not submitted), `pending_validation`, `validation_failed`, `submitted`, `foc_confirmed` (the losing carrier confirmed a date), `porting`, `completed`, `rejected`, `cancel_requested`, `cancelled`."},"currentCarrier":{"type":["string","null"],"description":"The losing carrier."},"accountNumber":{"type":"string","description":"Account number at the losing carrier, masked except the last 4 characters."},"pinOnFile":{"type":"boolean","description":"Whether a PIN is stored. The PIN itself is never returned."},"authorizedName":{"type":"string"},"businessName":{"type":"string"},"billingPhoneNumber":{"type":["string","null"]},"serviceAddress":{"type":"object","properties":{"street":{"type":"string"},"street2":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"}},"required":["street","city","state","zip"]},"portType":{"type":["string","null"],"enum":["full","partial"]},"requestedFocAt":{"type":["string","null"],"description":"The FOC date you requested (ISO 8601)."},"focDate":{"type":["string","null"],"description":"The date the losing carrier confirmed (ISO 8601)."},"blocker":{"type":["string","null"],"description":"What you must fix, from the carrier or validation. PATCH the fields, then submit again."},"setupError":{"type":["string","null"],"description":"Our own setup error, if any."},"numberId":{"type":["string","null"],"description":"The number id once the port completed."},"cancelledAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","phoneNumber","status","currentCarrier","accountNumber","pinOnFile","authorizedName","businessName","billingPhoneNumber","serviceAddress","portType","requestedFocAt","focDate","blocker","setupError","numberId","cancelledAt","createdAt","updatedAt"],"description":"A number port-in request. The PIN is never returned and provider internals never leave the server.","example":{"id":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f","phoneNumber":"+15555550177","status":"submitted","currentCarrier":"Example Telecom","accountNumber":"••••••5678","pinOnFile":true,"authorizedName":"Alex Morgan","businessName":"Acme Plumbing LLC","billingPhoneNumber":"+15555550177","serviceAddress":{"street":"123 Main St","city":"Richmond","state":"VA","zip":"23219"},"portType":"full","requestedFocAt":"2026-07-15T00:00:00.000Z","focDate":null,"blocker":null,"setupError":null,"numberId":null,"cancelledAt":null,"createdAt":"2026-07-01T12:00:00.000Z","updatedAt":"2026-07-01T12:30:00.000Z"}},"PortPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Port"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"PortNumber":{"type":"object","properties":{"id":{"type":"string"},"phoneNumber":{"type":"string"},"status":{"type":"string","description":"Same vocabulary as the port status."}},"required":["id","phoneNumber","status"]},"PortDocument":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["loa","invoice","other"]},"filename":{"type":"string"},"sizeBytes":{"type":"integer"},"createdAt":{"type":"string"}},"required":["id","kind","filename","sizeBytes","createdAt"],"description":"A document attached to a port request."},"PortEvent":{"type":"object","properties":{"id":{"type":"string"},"stage":{"type":"string","description":"The timeline stage."},"note":{"type":["string","null"]},"createdAt":{"type":"string"}},"required":["id","stage","note","createdAt"],"description":"One entry on the port request timeline."},"PortDetail":{"type":"object","properties":{"port":{"$ref":"#/components/schemas/Port"},"numbers":{"type":"array","items":{"$ref":"#/components/schemas/PortNumber"}},"documents":{"type":"array","items":{"$ref":"#/components/schemas/PortDocument"}},"events":{"type":"array","items":{"$ref":"#/components/schemas/PortEvent"},"description":"The timeline of what happened."}},"required":["port","numbers","documents","events"],"description":"A port request with its numbers, documents and timeline."},"PortResponse":{"type":"object","properties":{"port":{"$ref":"#/components/schemas/Port"}},"required":["port"]},"PortabilityResult":{"type":"object","properties":{"phoneNumber":{"type":"string"},"portable":{"type":"boolean"},"reason":{"type":"string","description":"Why it cannot be ported, when not portable."},"carrier":{"type":"string","description":"The losing carrier, when known."},"fastPortable":{"type":"boolean","description":"Whether the number qualifies for a fast port."}},"required":["phoneNumber","portable","fastPortable"],"description":"Whether one number can be ported.","example":{"phoneNumber":"+15555550177","portable":true,"carrier":"Example Telecom","fastPortable":true}},"PortabilityResultPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PortabilityResult"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"PortCreateRequest":{"type":"object","properties":{"phoneNumbers":{"type":"array","items":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"minItems":1,"maxItems":100,"description":"The numbers to port (1-100, unique, E.164)."},"currentCarrier":{"type":"string","minLength":1,"maxLength":100,"description":"The losing carrier."},"accountNumber":{"type":"string","minLength":1,"maxLength":64,"description":"Account number at the losing carrier."},"pin":{"type":"string","minLength":1,"maxLength":32,"description":"Account PIN / passcode. Never returned."},"authorizedName":{"type":"string","minLength":2,"maxLength":200,"description":"Person authorised to port, as on the carrier account."},"businessName":{"type":"string","minLength":2,"maxLength":200,"description":"Business name on the carrier account."},"billingPhoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The billing telephone number on the carrier account."},"serviceAddress":{"type":"object","properties":{"street":{"type":"string","minLength":1,"maxLength":200},"street2":{"type":"string","maxLength":200},"city":{"type":"string","minLength":1,"maxLength":100},"state":{"type":"string","minLength":2,"maxLength":50},"zip":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}},"required":["street","city","state","zip"],"description":"Service address on the carrier account."},"portType":{"type":"string","enum":["full","partial"],"description":"`full` ports every number on the account; `partial` ports some."},"requestedFocDate":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","format":"date"}],"description":"Requested FOC date (ISO date or date-time). The losing carrier confirms the real one."}},"required":["phoneNumbers","currentCarrier","accountNumber","pin","authorizedName","businessName","billingPhoneNumber","serviceAddress","portType"],"example":{"phoneNumbers":["+15555550177"],"currentCarrier":"Example Telecom","accountNumber":"12345678","pin":"4321","authorizedName":"Alex Morgan","businessName":"Acme Plumbing LLC","billingPhoneNumber":"+15555550177","serviceAddress":{"street":"123 Main St","city":"Richmond","state":"VA","zip":"23219"},"portType":"full"}},"PortUpdateRequest":{"type":"object","properties":{"currentCarrier":{"type":"string","minLength":1,"maxLength":100,"description":"The losing carrier."},"accountNumber":{"type":"string","minLength":1,"maxLength":64,"description":"Account number at the losing carrier."},"pin":{"type":"string","minLength":1,"maxLength":32,"description":"Account PIN."},"authorizedName":{"type":"string","minLength":2,"maxLength":200},"businessName":{"type":"string","minLength":2,"maxLength":200},"billingPhoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"serviceAddress":{"type":"object","properties":{"street":{"type":"string","minLength":1,"maxLength":200},"street2":{"type":"string","maxLength":200},"city":{"type":"string","minLength":1,"maxLength":100},"state":{"type":"string","minLength":2,"maxLength":50},"zip":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}},"required":["street","city","state","zip"],"description":"Service address."},"portType":{"type":"string","enum":["full","partial"]},"requestedFocDate":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string","format":"date"}]}},"description":"Fix fields after a rejection, then submit again. Every field is optional but at least one is required. The numbers on a request cannot change; open a new port instead."},"DomainRecord":{"type":"object","properties":{"type":{"type":"string","enum":["TXT","MX","CNAME"],"description":"DNS record type."},"host":{"type":"string","description":"The full host name to publish the record at."},"value":{"type":"string","description":"The exact value to publish."},"priority":{"type":["integer","null"],"description":"MX priority; null for other types."},"required":{"type":"boolean","description":"Whether verification needs this record. Recommended records improve delivery."},"purpose":{"type":"string","enum":["ownership","spf","dkim","dmarc","mx"],"description":"`ownership` (proves you control the domain), `spf`, `dkim` (message signing), `dmarc`, or `mx` (inbound only)."},"status":{"type":"string","enum":["verified","failed","pending","not_required","missing_optional"],"description":"The last check of this record: `verified`, `failed`, `pending` (not seen in DNS yet), `not_required`, or `missing_optional` (a recommended record that is not published)."}},"required":["type","host","value","priority","required","purpose","status"],"description":"One DNS record to publish for a sending domain."},"Domain":{"type":"object","properties":{"id":{"type":"string","description":"Domain id."},"domain":{"type":"string","description":"The sending domain, lowercase."},"status":{"type":"string","enum":["pending","verified","failed","degraded","suspended"],"description":"`pending` (records not verified yet), `verified`, `failed` (a required record is missing or wrong), `degraded` (was verified, a required record has since failed) or `suspended`."},"canSend":{"type":"boolean","description":"Whether this domain can send right now. True only when `verified`."},"records":{"type":"array","items":{"$ref":"#/components/schemas/DomainRecord"},"description":"The DNS records to publish, with their last status."},"checks":{"type":"object","properties":{"ownership":{"type":"string","enum":["verified","failed","pending","not_required","missing_optional"]},"spf":{"type":"string","enum":["verified","failed","pending","not_required","missing_optional"]},"dkim":{"type":"string","enum":["verified","failed","pending","not_required","missing_optional"]},"dmarc":{"type":"string","enum":["verified","failed","pending","not_required","missing_optional"]},"mx":{"type":"string","enum":["verified","failed","pending","not_required","missing_optional"]}},"required":["ownership","spf","dkim","dmarc","mx"],"description":"The last check of each record, keyed by purpose."},"reputation":{"type":["string","null"],"enum":["excellent","good","warn","poor","insufficient_data"],"description":"Sender reputation band: `excellent`, `good`, `warn`, `poor` or `insufficient_data`. Null until known."},"lastCheckedAt":{"type":["string","null"],"description":"When DNS was last checked (ISO 8601)."},"createdAt":{"type":"string","description":"ISO 8601."}},"required":["id","domain","status","canSend","records","checks","reputation","lastCheckedAt","createdAt"],"description":"An email sending domain. Publish `records` at your DNS provider, then call `POST /v1/domains/{id}/verify`. Only a `verified` domain can send.","example":{"id":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","domain":"example.com","status":"pending","canSend":false,"records":[{"type":"TXT","host":"example.com","value":"domain-verification=7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e","priority":null,"required":true,"purpose":"ownership","status":"pending"},{"type":"TXT","host":"example.com","value":"v=spf1 include:spf.example-mail.test ~all","priority":null,"required":false,"purpose":"spf","status":"missing_optional"},{"type":"TXT","host":"k1._domainkey.example.com","value":"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...","priority":null,"required":true,"purpose":"dkim","status":"pending"},{"type":"TXT","host":"_dmarc.example.com","value":"v=DMARC1; p=none;","priority":null,"required":false,"purpose":"dmarc","status":"missing_optional"}],"checks":{"ownership":"pending","spf":"missing_optional","dkim":"pending","dmarc":"missing_optional","mx":"not_required"},"reputation":null,"lastCheckedAt":null,"createdAt":"2026-07-01T12:00:00.000Z"}},"DomainPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"Email":{"type":"object","properties":{"id":{"type":"string","description":"Email id."},"status":{"type":"string","enum":["queued","sent","delivered","partially_delivered","bounced","failed"],"description":"Delivery state."},"channel":{"type":"string","enum":["email"],"description":"Always `email`."},"from":{"type":"string","description":"The sender, as `Name <address>` or a bare address."},"to":{"type":"array","items":{"type":"string"},"description":"Primary recipients."},"cc":{"type":"array","items":{"type":"string"},"description":"Carbon-copy recipients."},"bcc":{"type":"array","items":{"type":"string"},"description":"Blind-carbon-copy recipients."},"replyTo":{"type":["string","null"],"description":"Where replies go; null when not set."},"subject":{"type":"string","description":"The subject line."},"recipients":{"type":"integer","description":"Recipients accepted for delivery (to + cc + bcc, minus any suppressed). This is the billable count."},"suppressed":{"type":"array","items":{"type":"string"},"description":"Recipients we skipped because an earlier email to them bounced, drew a complaint, or they unsubscribed. They are not billed."},"sandbox":{"type":"boolean","description":"True when every recipient was an reserved sandbox test address: the email was not delivered and not billed."},"tags":{"type":"array","items":{"type":"string"},"description":"Your labels for this email."},"metadata":{"type":"object","additionalProperties":{"type":"string"},"description":"Your key-value data for this email."},"externalRef":{"type":["string","null"],"description":"Your own reference for this email; null when not set."},"createdAt":{"type":"string","description":"When the email was created (ISO 8601)."},"updatedAt":{"type":"string","description":"When the email last changed (ISO 8601)."}},"required":["id","status","channel","from","to","cc","bcc","replyTo","subject","recipients","suppressed","sandbox","tags","metadata","externalRef","createdAt","updatedAt"],"description":"An email you sent. The subject and recipients are returned; the message bodies are returned only when you retrieve a single email.","example":{"id":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","status":"queued","channel":"email","from":"Riverside Plumbing <jobs@example.com>","to":["dana@example.com"],"cc":[],"bcc":[],"replyTo":null,"subject":"Your estimate is ready","recipients":1,"suppressed":[],"sandbox":false,"tags":["estimate"],"metadata":{"jobId":"job_1042"},"externalRef":null,"createdAt":"2026-07-01T15:04:05.000Z","updatedAt":"2026-07-01T15:04:05.000Z"}},"EmailPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Email"}}},"required":["data"]}],"description":"A page of emails, newest first."},"SendEmailRequest":{"type":"object","properties":{"from":{"type":"string","minLength":3,"maxLength":400,"description":"The sender: `jobs@example.com` or `Riverside Plumbing <jobs@example.com>`. The address must be on a [sending domain](#tag/Email-domains) you added and verified."},"to":{"anyOf":[{"type":"string","minLength":3,"maxLength":320},{"type":"array","items":{"type":"string","minLength":3,"maxLength":320},"maxItems":50}],"description":"Recipient address, or an array of addresses. At most 50 recipients in total across `to`, `cc` and `bcc`."},"cc":{"anyOf":[{"type":"string","minLength":3,"maxLength":320},{"type":"array","items":{"type":"string","minLength":3,"maxLength":320},"maxItems":50}],"description":"Carbon-copy address or addresses."},"bcc":{"anyOf":[{"type":"string","minLength":3,"maxLength":320},{"type":"array","items":{"type":"string","minLength":3,"maxLength":320},"maxItems":50}],"description":"Blind-carbon-copy address or addresses. Recipients never see each other on bcc."},"replyTo":{"type":"string","minLength":3,"maxLength":320,"description":"Address replies should go to."},"subject":{"type":"string","minLength":1,"maxLength":998,"description":"The subject line (up to 998 characters, no line breaks)."},"html":{"type":"string","maxLength":1000000,"description":"The HTML body (up to 1 MB). Provide `html`, `text`, or both."},"text":{"type":"string","maxLength":1000000,"description":"The plain-text body (up to 1 MB). Sent alongside `html` as the text alternative."},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":64},"maxItems":10,"description":"Up to 10 short labels (64 characters each) stored with the email."},"metadata":{"type":"object","additionalProperties":{"type":"string","maxLength":500},"description":"Up to 20 key-value pairs (string values) stored with the email."},"externalRef":{"type":"string","maxLength":255,"description":"Your own reference for this email, returned as-is."}},"required":["from","to","subject"],"description":"Send an email.","example":{"from":"Riverside Plumbing <jobs@example.com>","to":"dana@example.com","subject":"Your estimate is ready","html":"<p>Tap to review and approve.</p>"}},"EmailRecipientStatus":{"type":"object","properties":{"address":{"type":"string","description":"The recipient address."},"kind":{"type":"string","enum":["to","cc","bcc"],"description":"`to`, `cc` or `bcc`."},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","complained","suppressed"],"description":"Where delivery stands for this recipient: `queued`, `sent`, `deferred` (temporary delay, still retrying), `delivered`, `bounced`, `failed`, `complained`, or `suppressed` (skipped, not billed)."},"lastEventAt":{"type":["string","null"],"description":"When the latest delivery event for this recipient happened; null before any."}},"required":["address","kind","status","lastEventAt"],"example":{"address":"dana@example.com","kind":"to","status":"delivered","lastEventAt":"2026-07-01T15:04:09.000Z"}},"EmailEvent":{"type":"object","properties":{"type":{"type":"string","enum":["sent","delivered","deferred","bounced","failed","opened","clicked","complained","unsubscribed"],"description":"What happened: `sent`, `delivered`, `deferred`, `bounced`, `failed`, `opened`, `clicked`, `complained` or `unsubscribed`."},"recipient":{"type":["string","null"],"description":"The recipient address. Null for a bcc recipient we could not tell apart from the email's other bcc recipients."},"occurredAt":{"type":"string","description":"When it happened (ISO 8601)."},"bounce":{"type":"object","properties":{"class":{"type":"string","enum":["hard","soft","administrative","expired","unknown"]},"code":{"type":["integer","null"]},"message":{"type":["string","null"]}},"required":["class","code","message"],"description":"On `bounced` and `failed`: `class` is `hard` (the address does not exist), `soft`, `administrative`, `expired` or `unknown`, plus the numeric `code` and a short `message`."},"url":{"type":"string","description":"On `clicked`: the link that was clicked."},"method":{"type":"string","description":"On `unsubscribed`: how (`link` or `one_click`)."}},"required":["type","recipient","occurredAt"],"example":{"type":"bounced","recipient":"gone@example.com","occurredAt":"2026-07-01T15:04:09.000Z","bounce":{"class":"hard","code":30001,"message":"Mailbox does not exist"}}},"EmailEventPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailEvent"}}},"required":["data"]}],"description":"A page of events, newest first."},"EmailDetail":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["queued","sent","delivered","partially_delivered","bounced","failed"]},"channel":{"type":"string","enum":["email"]},"from":{"type":"string"},"to":{"type":"array","items":{"type":"string"}},"cc":{"type":"array","items":{"type":"string"}},"bcc":{"type":"array","items":{"type":"string"}},"replyTo":{"type":["string","null"]},"subject":{"type":"string"},"recipients":{"type":"integer"},"suppressed":{"type":"array","items":{"type":"string"}},"sandbox":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string"}},"metadata":{"type":"object","additionalProperties":{"type":"string"}},"externalRef":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"html":{"type":["string","null"],"description":"The HTML body as you sent it; null if you sent none. Only on this endpoint, never on lists."},"text":{"type":["string","null"],"description":"The plain-text body as you sent it; null if you sent none. Only on this endpoint, never on lists."},"recipientStatuses":{"type":"array","items":{"$ref":"#/components/schemas/EmailRecipientStatus"},"description":"Per-recipient delivery state."},"events":{"type":"array","items":{"$ref":"#/components/schemas/EmailEvent"},"description":"The newest 100 delivery events."}},"required":["id","status","channel","from","to","cc","bcc","replyTo","subject","recipients","suppressed","sandbox","tags","metadata","externalRef","createdAt","updatedAt","html","text","recipientStatuses","events"],"description":"An email with its message bodies, per-recipient state and recent delivery events."},"EmailSuppression":{"type":"object","properties":{"address":{"type":"string","description":"The suppressed address (lowercase)."},"reason":{"type":"string","enum":["hard_bounce","complaint","unsubscribe","manual"],"description":"Why: `hard_bounce`, `complaint`, `unsubscribe` (added automatically) or `manual` (you added it)."},"emailId":{"type":["string","null"],"description":"The email that caused it, when it was added automatically; otherwise null."},"createdAt":{"type":"string","description":"When it was added (ISO 8601)."}},"required":["address","reason","emailId","createdAt"],"description":"An address you will not send to. Emails to it skip the address (listed in `suppressed` on the email, not billed).","example":{"address":"gone@example.com","reason":"hard_bounce","emailId":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e","createdAt":"2026-07-01T15:04:09.000Z"}},"EmailSuppressionPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/EmailSuppression"}}},"required":["data"]}],"description":"A page of suppressed addresses, newest first."},"CreateEmailSuppressionRequest":{"type":"object","properties":{"address":{"type":"string","minLength":3,"maxLength":320,"description":"The address to stop sending to."},"reason":{"type":"string","enum":["manual"],"description":"Always `manual` (the default)."}},"required":["address"],"example":{"address":"optout@example.com"}},"SoftphoneDevice":{"type":"object","properties":{"id":{"type":"string","description":"Device id. Use it as a `webrtc` destination in a number route."},"userId":{"type":"string","description":"Your own identifier for the user the device belongs to. Opaque to Mittis."},"sipUsername":{"type":"string","description":"The device’s SIP username."},"sipUri":{"type":"string","description":"The registrable SIP URI that route destinations resolve to."},"label":{"type":"string","description":"Device label; with `userId` it identifies the device."},"enabled":{"type":"boolean","description":"Disabled devices are not dialed."},"signedOut":{"type":"boolean","description":"True once the owner signed out of the app (`detach`) and until the device proves a live session again. A signed-out device is never dialed. Distinct from `enabled: false`."},"presence":{"type":"object","properties":{"status":{"type":"string","enum":["online","offline"]},"lastSeenAt":{"type":["string","null"]}},"required":["status","lastSeenAt"],"description":"Present on `GET /v1/webrtc/devices`. `status` already accounts for a stale heartbeat (a stale `online` reads as `offline`)."}},"required":["id","userId","sipUsername","sipUri","label","enabled"],"description":"A browser or mobile softphone endpoint belonging to one of your users.","example":{"id":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6","userId":"user_123","sipUsername":"mittis_d1e2f3a4","sipUri":"sip:mittis_d1e2f3a4@sip.example.net","label":"softphone","enabled":true,"signedOut":false,"presence":{"status":"online","lastSeenAt":"2026-07-01T15:00:00.000Z"}}},"SoftphoneDeviceList":{"type":"object","properties":{"devices":{"type":"array","items":{"$ref":"#/components/schemas/SoftphoneDevice"},"description":"Legacy key; the same array as `data`."},"data":{"type":"array","items":{"$ref":"#/components/schemas/SoftphoneDevice"}},"hasMore":{"type":"boolean"},"nextCursor":{"type":["string","null"]}},"required":["devices","data","hasMore","nextCursor"],"description":"Your devices in the shared list envelope (always one whole page)."},"SoftphoneToken":{"type":"object","properties":{"deviceId":{"type":"string","description":"The device."},"sipUri":{"type":"string","description":"The device’s SIP URI."},"login_token":{"type":"string","description":"Short-lived login token. Pass it straight to the voice client SDK as `login_token`. Re-mint on registration failure."},"expiresAt":{"type":"string","description":"When the token expires (ISO 8601)."},"ttlSeconds":{"type":"integer","description":"Lifetime in seconds."}},"required":["deviceId","sipUri","login_token","expiresAt","ttlSeconds"]},"SoftphoneCredential":{"type":"object","properties":{"deviceId":{"type":"string"},"sipUsername":{"type":"string"},"sipPassword":{"type":"string","description":"A secret, long-lived SIP password for native push re-authentication. Treat it like a password: never log it."},"sipUri":{"type":"string"}},"required":["deviceId","sipUsername","sipPassword","sipUri"],"description":"A long-lived SIP credential for native VoIP-push re-authentication (the mobile app). Unlike a token it does not expire. If the stored device predates password capture the credential is transparently re-provisioned (a new username and password)."},"SoftphoneCall":{"type":"object","properties":{"callId":{"type":"string","description":"The created call. Follow it with `GET /v1/calls/{id}` or the `call.*` events."},"from":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The caller id the callee will see: one of your own numbers."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number being called (E.164)."}},"required":["callId","from","to"],"example":{"callId":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8","from":"+15555550100","to":"+15555550142"}},"Subaccount":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"type":"string","description":"ISO 8601."},"smsEnabled":{"type":"boolean","description":"Whether the sub-account may send texts."},"voiceEnabled":{"type":"boolean","description":"Whether the sub-account may place and receive calls."},"emailEnabled":{"type":"boolean","description":"Whether the sub-account may register sending domains and send email."}},"required":["id","name","slug","createdAt","smsEnabled","voiceEnabled","emailEnabled"],"description":"A sub-account (a child tenant of your agency).","example":{"id":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11","name":"Acme Plumbing","slug":"acme-plumbing","smsEnabled":true,"voiceEnabled":true,"emailEnabled":true,"createdAt":"2026-06-01T12:00:00.000Z"}},"SubaccountSummary":{"allOf":[{"$ref":"#/components/schemas/Subaccount"},{"type":"object","properties":{"plan":{"type":"string"},"numbers":{"type":"integer","description":"Active numbers owned by the sub-account."},"usage":{"type":"object","additionalProperties":{"type":"number"},"description":"This period’s usage meters."}},"required":["plan","numbers","usage"]}],"description":"A roster entry with at-a-glance stats for the current period.","example":{"id":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11","name":"Acme Plumbing","slug":"acme-plumbing","plan":"subaccount","smsEnabled":true,"voiceEnabled":true,"emailEnabled":true,"createdAt":"2026-06-01T12:00:00.000Z","numbers":2,"usage":{"messages":1240,"segments":1411,"price_cents":1594}}},"SubaccountPage":{"allOf":[{"$ref":"#/components/schemas/PageEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SubaccountSummary"}}},"required":["data"]}],"description":"A page of results in the shared list envelope."},"SubaccountDetail":{"type":"object","properties":{"subaccount":{"$ref":"#/components/schemas/Subaccount"},"usage":{"$ref":"#/components/schemas/Usage"},"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"},"description":"The sub-account’s API keys."},"webhooks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"createdAt":{"type":"string"}},"required":["id","url","createdAt"]}}},"required":["subaccount","usage","keys","webhooks"],"description":"A sub-account with its usage, keys and webhook endpoints."},"SubaccountResponse":{"type":"object","properties":{"subaccount":{"$ref":"#/components/schemas/Subaccount"}},"required":["subaccount"]},"SubaccountProvisioned":{"type":"object","properties":{"alreadyProvisioned":{"type":"boolean","description":"True when a sub-account with that slug already belonged to you (a safe replay): `apiKey` and `webhook` are then null."},"subaccount":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"type":"string","description":"ISO 8601."}},"required":["id","name","slug","createdAt"]},"apiKey":{"type":["object","null"],"properties":{"id":{"type":"string"},"secret":{"type":"string","description":"The full key. Shown once; store it, or use your agency key with `Mittis-Subaccount` and never hold child keys."},"displayHint":{"type":"string"},"mode":{"type":"string","enum":["live","test"]}},"required":["id","secret","displayHint","mode"]},"webhook":{"type":["object","null"],"properties":{"id":{"type":"string"},"url":{"type":"string"},"secret":{"type":"string","description":"Signing secret, shown once."}},"required":["id","url","secret"],"description":"Present when `webhookUrl` was supplied."}},"required":["alreadyProvisioned","subaccount","apiKey","webhook"],"description":"The result of provisioning a sub-account."},"SubaccountHeader":{"type":"string","format":"uuid","description":"Agency keys only. The id of one of your sub-accounts; the request then runs as that sub-account (read-write). Anything but your own direct child returns 403. Ignored on agency-level routes, which reject it.","example":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11"},"IdempotencyKeyHeader":{"type":"string","minLength":1,"maxLength":255,"description":"A unique value (e.g. a UUID) per logical request. A retry with the same key returns the original result without repeating the action.","example":"order-48213-confirmation"}},"parameters":{"SubaccountHeader":{"schema":{"$ref":"#/components/schemas/SubaccountHeader"},"required":false,"name":"Mittis-Subaccount","in":"header"},"IdempotencyKeyHeader":{"schema":{"$ref":"#/components/schemas/IdempotencyKeyHeader"},"required":false,"name":"Idempotency-Key","in":"header"}}},"paths":{"/v1/messages":{"post":{"operationId":"sendMessage","tags":["Messages"],"summary":"Send a message","description":"Sends an SMS or MMS. The send is queued with the carrier and the response returns immediately with the new message; follow its delivery with `message.status` webhooks or `GET /v1/messages/{id}`. Requests are rate limited per account (`429 rate_limited`). Use `Idempotency-Key` to make retries safe: a repeated key returns the original message with `Idempotent-Replayed: true` and does not send again.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"},{"$ref":"#/components/parameters/IdempotencyKeyHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}}},"responses":{"201":{"description":"The message was accepted.","headers":{"Idempotent-Replayed":{"description":"`true` when this is the original message returned for a repeated `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Mittis-Budget-Warning":{"description":"`true` when this send pushed monthly spend past the soft threshold of your spend limit.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProviderError"}}},"get":{"operationId":"listMessages","tags":["Messages"],"summary":"List messages","description":"Messages in both directions, newest first, with cursor pagination. `phone` filters to messages sent to or from one number.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":500,"default":100,"description":"Page size (1-500). Default 100."},"required":false,"description":"Page size (1-500). Default 100.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","description":"Only messages to or from this number."},"required":false,"description":"Only messages to or from this number.","name":"phone","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of messages.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagePage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/messages/{id}":{"get":{"operationId":"getMessage","tags":["Messages"],"summary":"Retrieve a message","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The message id."},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The message.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/conversations":{"get":{"operationId":"listConversations","tags":["Conversations"],"summary":"List conversations","description":"One entry per counterparty number, built from the 500 most recent messages, newest thread first.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Conversation summaries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationPage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/conversations/{phone}":{"get":{"operationId":"getConversation","tags":["Conversations"],"summary":"Retrieve a conversation","description":"The message thread with one number, oldest first, built from the 500 most recent messages. Returns an empty `data` array when there are none.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The counterparty number (E.164, URL-encode the `+`).","example":"+15555550142"},"required":true,"name":"phone","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The thread.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationThread"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/blocked-numbers":{"get":{"operationId":"listBlockedNumbers","tags":["Blocked numbers"],"summary":"List blocked numbers","description":"Numbers whose inbound calls are hung up before anything rings. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Blocked numbers, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockedNumberPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BlockedNumber"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"blockNumber","tags":["Blocked numbers"],"summary":"Block a number","description":"Adds a number to the inbound blocklist. Blocking an already-blocked number updates its reason (and confirms an auto-suggested entry).","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number to block (E.164)."},"reason":{"type":"string","maxLength":200,"description":"Free-text note (max 200 characters)."},"autoSuggested":{"type":"boolean","description":"Mark the entry as a suggestion that is not enforced until confirmed. Omit for a normal block."}},"required":["phone"]},"example":{"phone":"+15555550199","reason":"Robocaller"}}}},"responses":{"201":{"description":"The blocklist entry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BlockedNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/blocked-numbers/{phone}":{"delete":{"operationId":"unblockNumber","tags":["Blocked numbers"],"summary":"Unblock a number","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The blocked number (E.164, URL-encode the `+`).","example":"+15555550199"},"required":true,"name":"phone","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The number is no longer blocked.","content":{"application/json":{"schema":{"type":"object","properties":{"phone":{"type":"string"},"blocked":{"type":"boolean","enum":[false]}},"required":["phone","blocked"],"example":{"phone":"+15555550199","blocked":false}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/numbers":{"get":{"operationId":"listNumbers","tags":["Numbers"],"summary":"List numbers","description":"Your numbers. Released numbers are hidden unless `include=released`. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"Set to `released` to also list numbers that were released back to the carrier."},"required":false,"description":"Set to `released` to also list numbers that were released back to the carrier.","name":"include","in":"query"},{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your numbers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumberPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PhoneNumber"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/numbers/search":{"post":{"operationId":"searchAvailableNumbers","tags":["Numbers"],"summary":"Search available numbers","description":"Finds numbers you can buy, each with its monthly rental price. Local search needs a three-digit `areaCode`; narrow it with `locality` (city), `contains` (digits the number must include) and `capabilities`. Searching does not reserve a number. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["local","tollfree"],"default":"local","description":"`local` (default) or `tollfree`."},"areaCode":{"type":"string","description":"Three-digit area code. Required when `type` is `local`."},"locality":{"type":"string","minLength":1,"maxLength":64,"description":"City to search in (local numbers), e.g. `Richmond`."},"contains":{"type":"string","pattern":"^\\d{1,7}$","description":"Digits the number must contain (1-7 digits), e.g. `555`."},"capabilities":{"type":"array","items":{"type":"string","enum":["sms","mms","voice"]},"maxItems":3,"description":"Only numbers that support all of these: `sms`, `mms`, `voice`."}}},"example":{"type":"local","areaCode":"804","contains":"555","capabilities":["sms","voice"]}}}},"responses":{"200":{"description":"Matching numbers.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailableNumberPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AvailableNumber"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}":{"get":{"operationId":"getNumber","tags":["Numbers"],"summary":"Retrieve a number","description":"One of your numbers, including released ones. Another account’s id is a `404`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateNumber","tags":["Numbers"],"summary":"Update a number","description":"Sets or clears the number’s `label`. The label is trimmed; an empty string or null clears it. Any member or API key may do this.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":["string","null"],"maxLength":256,"description":"Up to 64 characters after trimming; empty or null clears it."}},"required":["label"]},"example":{"label":"Main line"}}}},"responses":{"200":{"description":"The updated number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/numbers/buy":{"post":{"operationId":"buyNumber","tags":["Numbers"],"summary":"Buy a number","description":"Purchases a number from search results and bills the first month of rental. Wallet-enabled accounts need a funded balance (`402 payment_required`). Another buyer may take the number first (`409 conflict`).","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number to buy (E.164), from a search result."}},"required":["phoneNumber"]},"example":{"phoneNumber":"+15555550123"}}}},"responses":{"201":{"description":"The purchased number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}/assign":{"post":{"operationId":"assignNumberToCampaign","tags":["Numbers"],"summary":"Assign a number to a campaign","description":"Links the number to a registered 10DLC campaign so it can send, or pass `campaignId: null` to unlink it. The campaign must already be registered (`409 conflict` otherwise).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"campaignId":{"type":["string","null"],"description":"The campaign to assign, or null to clear the assignment."}},"required":["campaignId"]},"example":{"campaignId":"7c9e6679-7425-40de-944b-e07fc1f90ae7"}}}},"responses":{"200":{"description":"The updated number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}/route":{"get":{"operationId":"getNumberRoute","tags":["Numbers"],"summary":"Get a number’s call route","description":"Where inbound calls to this number ring. `route` is null until one is set.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The route and supported features.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallRouteResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"operationId":"setNumberRoute","tags":["Numbers"],"summary":"Set a number’s call route","description":"Replaces the route. Destinations are validated: PSTN numbers must be E.164, SIP destinations a `sip:` URI, and softphone destinations one of your enabled devices. A released number returns `409 conflict`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCallRouteRequest"}}}},"responses":{"200":{"description":"The saved route.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallRouteWrite"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/numbers/{id}/verify-tollfree":{"post":{"operationId":"verifyTollFreeNumber","tags":["Numbers"],"summary":"Submit toll-free verification","description":"Submits the carrier toll-free verification form, required before a toll-free number can text. Status moves `pending` → `verified` | `rejected` | `action_required`; resubmit after a rejection. Test keys never reach the carrier.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"businessName":{"type":"string","minLength":1,"maxLength":500},"website":{"type":"string","maxLength":500,"format":"uri"},"address":{"type":"object","properties":{"street":{"type":"string","minLength":1,"maxLength":500},"street2":{"type":"string","maxLength":500},"city":{"type":"string","minLength":1,"maxLength":500},"state":{"type":"string","minLength":2,"maxLength":500},"zip":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}},"required":["street","city","state","zip"]},"contact":{"type":"object","properties":{"firstName":{"type":"string","minLength":1,"maxLength":500},"lastName":{"type":"string","minLength":1,"maxLength":500},"email":{"type":"string","maxLength":500,"format":"email"},"phone":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},"required":["firstName","lastName","email","phone"]},"messageVolume":{"type":"string","enum":["10","100","1,000","10,000","100,000","250,000","500,000","750,000","1,000,000","5,000,000","10,000,000+"]},"useCase":{"type":"string","enum":["2FA","App Notifications","Appointments","Auctions","Auto Repair Services","Bank Transfers","Billing","Booking Confirmations","Business Updates","COVID-19 Alerts","Career Training","Chatbot","Conversational / Alerts","Courier Services & Deliveries","Emergency Alerts","Events & Planning","Financial Services","Fraud Alerts","Fundraising","General Marketing","General School Updates","HR / Staffing","Healthcare Alerts","Housing Community Updates","Insurance Services","Job Dispatch","Legal Services","Mixed","Motivational Reminders","Notary Notifications","Order Notifications","Political","Public Works","Real Estate Services","Religious Services","Repair and Diagnostics Alerts","Rewards Program","Surveys","System Alerts","Voting Reminders","Waitlist Alerts","Webinar Reminders","Workshop Alerts"]},"useCaseSummary":{"type":"string","minLength":1,"maxLength":500},"sampleMessage":{"type":"string","minLength":1,"maxLength":1000},"optInWorkflow":{"type":"string","minLength":1,"maxLength":500},"optInImageUrls":{"type":"array","items":{"type":"string","maxLength":2083,"format":"uri"},"minItems":1,"maxItems":10},"additionalInfo":{"type":"string","maxLength":500},"businessRegistrationNumber":{"type":"string","minLength":1,"maxLength":500},"businessRegistrationType":{"type":"string","minLength":1,"maxLength":500,"default":"EIN"},"businessRegistrationCountry":{"type":"string","pattern":"^[A-Za-z]{2}$","default":"US"},"entityType":{"type":"string","enum":["SOLE_PROPRIETOR","PRIVATE_PROFIT","PUBLIC_PROFIT","NON_PROFIT","GOVERNMENT"]},"doingBusinessAs":{"type":"string","maxLength":500},"privacyPolicyUrl":{"type":"string","maxLength":500},"termsUrl":{"type":"string","maxLength":500},"optInKeywords":{"type":"string","maxLength":500},"optInConfirmationMessage":{"type":"string","maxLength":500},"helpMessage":{"type":"string","maxLength":500},"ageGated":{"type":"boolean"}},"required":["businessName","website","address","contact","messageVolume","useCase","useCaseSummary","sampleMessage","optInWorkflow","optInImageUrls","businessRegistrationNumber"]}}}},"responses":{"200":{"description":"The number with its new verification status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}/caller-id-name":{"put":{"operationId":"setCallerIdName","tags":["Numbers"],"summary":"Set the outbound caller-ID name","description":"Lists a caller-ID name (up to 15 letters, digits and spaces) for outbound calls. Status becomes `pending`; carriers take days to propagate.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Up to 15 characters: letters, digits and spaces."}},"required":["name"]},"example":{"name":"ACME PLUMBING"}}}},"responses":{"200":{"description":"The updated number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}},"delete":{"operationId":"clearCallerIdName","tags":["Numbers"],"summary":"Remove the outbound caller-ID name","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The updated number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}/emergency":{"put":{"operationId":"enableEmergencyCalling","tags":["Numbers"],"summary":"Enable emergency calling (E911)","description":"Validates the dispatch address with the carrier, then enables emergency calling. When the carrier proposes a correction the response is `422 address_suggestion` with the corrected address in `error.details.suggested`; resubmit that address. Enabled numbers carry a monthly emergency-calling fee.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"address":{"type":"object","properties":{"street":{"type":"string","minLength":1,"maxLength":200},"street2":{"type":"string","maxLength":200},"city":{"type":"string","minLength":1,"maxLength":100},"state":{"type":"string","pattern":"^[A-Za-z]{2}$"},"zip":{"type":"string","pattern":"^\\d{5}(-\\d{4})?$"}},"required":["street","city","state","zip"]},"businessName":{"type":"string","minLength":1,"maxLength":100},"contactFirstName":{"type":"string","minLength":1,"maxLength":50},"contactLastName":{"type":"string","minLength":1,"maxLength":50}},"required":["address"]},"example":{"address":{"street":"123 Main St","city":"Richmond","state":"VA","zip":"23219"},"businessName":"Acme Plumbing"}}}},"responses":{"200":{"description":"The updated number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/Unprocessable"},"502":{"$ref":"#/components/responses/ProviderError"}}},"delete":{"operationId":"disableEmergencyCalling","tags":["Numbers"],"summary":"Disable emergency calling (E911)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The updated number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}/release":{"post":{"operationId":"releaseNumber","tags":["Numbers"],"summary":"Release a number","description":"Returns the number to the carrier. This cannot be undone. The request must repeat the number as a typed confirmation, and it is refused (`409 conflict`) while the number is on an open port request.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirmPhoneNumber":{"type":"string","minLength":1,"description":"Must equal the number’s E.164 exactly."}},"required":["confirmPhoneNumber"]},"example":{"confirmPhoneNumber":"+15555550100"}}}},"responses":{"200":{"description":"The number, now `released`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhoneNumber"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/numbers/{id}/voicemail-greeting":{"put":{"operationId":"uploadVoicemailGreeting","tags":["Numbers"],"summary":"Upload a voicemail greeting","description":"Stores a custom greeting. Send the raw audio bytes as the request body with `Content-Type: audio/wav` or `audio/mpeg` (max 5 MB; convert other formats first). It plays instead of the text greeting whenever voicemail is enabled on the route.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"description":"Raw WAV or MP3 audio.","required":true,"content":{"audio/wav":{"schema":{"type":"string","format":"binary"}},"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"The greeting was stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoicemailGreeting"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}},"delete":{"operationId":"deleteVoicemailGreeting","tags":["Numbers"],"summary":"Remove the voicemail greeting","description":"Reverts to the text greeting.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The number id (from `GET /v1/numbers`).","example":"a3c1d2e4-5b6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"204":{"description":"The custom greeting was removed."},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/brands":{"get":{"operationId":"listBrands","tags":["Brands"],"summary":"List brands","description":"Your registered brands, newest first. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your brands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Brand"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createBrand","tags":["Brands"],"summary":"Register a brand","description":"Registers a brand identity with the registry, without a campaign. Use `POST /v1/registrations` to register a brand and campaign together.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandRegistrationRequest"}}}},"responses":{"201":{"description":"The brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/brands/{id}":{"get":{"operationId":"getBrand","tags":["Brands"],"summary":"Retrieve a brand","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The brand id.","example":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateBrand","tags":["Brands"],"summary":"Update a brand","description":"Edits the brand’s presentation and contact fields. A registered brand’s identity (legal name, tax id, entity type) is immutable, and this does not resubmit the brand; use `resubmit` for a rejected brand. `pageConfig` designs the hosted opt-in page. Unknown fields are rejected.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The brand id.","example":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"displayName":{"type":"string"},"website":{"type":"string"},"vertical":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"street":{"type":"string"},"city":{"type":"string"},"state":{"type":"string"},"postalCode":{"type":"string"},"country":{"type":"string"},"businessContactEmail":{"type":"string"},"brandRelationship":{"type":"string","enum":["BASIC_ACCOUNT","SMALL_ACCOUNT","MEDIUM_ACCOUNT","LARGE_ACCOUNT","KEY_ACCOUNT"]},"pageConfig":{"type":"object","properties":{"logoUrl":{"type":"string","format":"uri"},"headline":{"type":"string","maxLength":160},"descriptor":{"type":"string","maxLength":200},"aboutUs":{"type":"string","maxLength":4000},"brandColor":{"type":"string","pattern":"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"},"primaryBgColor":{"type":"string","pattern":"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"},"secondaryBgColor":{"type":"string","pattern":"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"},"primaryTextColor":{"type":"string","pattern":"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"},"secondaryTextColor":{"type":"string","pattern":"^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$"},"webhookUrl":{"type":"string","format":"uri"},"submitLabel":{"type":"string","maxLength":60},"successMessage":{"type":"string","maxLength":400},"useAsWebsite":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}}}},"responses":{"200":{"description":"The updated brand.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/brands/{id}/resubmit":{"post":{"operationId":"resubmitBrand","tags":["Brands"],"summary":"Resubmit a rejected brand","description":"Re-registers a rejected or failed brand using its stored identity. An approved brand returns `409 conflict`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The brand id.","example":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The brand with its new status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Brand"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/brands/{id}/vetting":{"post":{"operationId":"requestBrandVetting","tags":["Brands"],"summary":"Request external vetting","description":"Requests external vetting, which raises campaign acceptance and carrier throughput. The brand must already be registered (`409 conflict` otherwise).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The brand id.","example":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","minLength":1,"description":"The vetting provider."},"vettingClass":{"type":"string","minLength":1,"description":"The vetting class. Defaults to `STANDARD`."}},"required":["provider"]},"example":{"provider":"AEGIS"}}}},"responses":{"200":{"description":"The brand and the vetting request id.","content":{"application/json":{"schema":{"type":"object","properties":{"brand":{"$ref":"#/components/schemas/Brand"},"vettingId":{"type":"string"}},"required":["brand","vettingId"],"description":"Vetting result."}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/brands/{id}/campaign-description":{"post":{"operationId":"draftCampaignDescription","tags":["Brands"],"summary":"Draft a campaign description","description":"AI-assist: expands a one-line business brief into a full, compliant campaign description. When `descriptor` is omitted the brand’s saved page descriptor is used; with neither the request fails validation.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The brand id.","example":"2e5f3a41-8d7c-4b9a-a1b2-c3d4e5f60718"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"descriptor":{"type":"string","maxLength":200,"description":"A short brief, e.g. \"cleaning windows and carpets\" (max 200 characters)."}}},"example":{"descriptor":"residential plumbing and drain cleaning"}}}},"responses":{"200":{"description":"The drafted description.","content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","minLength":40,"maxLength":1024}},"required":["description"],"example":{"description":"Acme Plumbing sends appointment reminders and service updates to existing customers who opted in..."}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/campaigns":{"get":{"operationId":"listCampaigns","tags":["Campaigns"],"summary":"List campaigns","description":"Your campaigns with their brand name and number count, newest first. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your campaigns.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignSummaryPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CampaignSummary"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createCampaign","tags":["Campaigns"],"summary":"Register a campaign","description":"Registers a campaign under an existing brand. Approval is asynchronous; poll `GET /v1/campaigns/{id}` for its `status`.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CampaignCreateRequest"}}}},"responses":{"201":{"description":"The campaign.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/campaigns/{id}":{"get":{"operationId":"getCampaign","tags":["Campaigns"],"summary":"Retrieve a campaign","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The campaign id.","example":"7c9e6679-7425-40de-944b-e07fc1f90ae7"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The campaign.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateCampaign","tags":["Campaigns"],"summary":"Update a campaign","description":"Edits the campaign’s descriptive content, links, keywords and flags. The carrier-vetted content of an approved campaign is not changed in place. Unknown fields are rejected.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The campaign id.","example":"7c9e6679-7425-40de-944b-e07fc1f90ae7"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"description":{"type":"string","minLength":1},"sampleMessages":{"type":"array","items":{"type":"string"},"minItems":1},"optInDetails":{"type":"string","minLength":1},"ctaDetails":{"type":"string"},"subscriberOptin":{"type":"boolean"},"subscriberOptout":{"type":"boolean"},"subscriberHelp":{"type":"boolean"},"embeddedLink":{"type":"boolean"},"embeddedPhone":{"type":"boolean"},"numberPool":{"type":"boolean"},"ageGated":{"type":"boolean"},"directLending":{"type":"boolean"},"affiliateMarketing":{"type":"boolean"},"termsAndConditions":{"type":"boolean"},"optinKeywords":{"type":"string"},"optinMessage":{"type":"string"},"optoutKeywords":{"type":"string"},"optoutMessage":{"type":"string"},"helpKeywords":{"type":"string"},"helpMessage":{"type":"string"},"privacyPolicyLink":{"type":"string"},"termsAndConditionsLink":{"type":"string"},"websiteUrl":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"The updated campaign.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Campaign"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/registrations":{"post":{"operationId":"submitRegistration","tags":["Registration"],"summary":"Register a brand and campaign","description":"Registers a brand and its first campaign in one call.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationRequest"}}}},"responses":{"201":{"description":"The brand and campaign.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationResult"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/onboarding/draft":{"post":{"operationId":"draftRegistration","tags":["Registration"],"summary":"Draft a registration with AI","description":"AI-assist: drafts a compliant brand and campaign from business info, automatically fixing it until the approval predictor reads `high` (or the retry limit is hit). Nothing is registered.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BusinessInfo"}}}},"responses":{"200":{"description":"The draft, its prediction and the number of fix passes.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationDraftResult"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"}}}},"/v1/onboarding/predict":{"post":{"operationId":"predictRegistrationApproval","tags":["Registration"],"summary":"Score a registration draft","description":"AI-assist: scores an edited draft’s approval likelihood and lists what to improve.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationDraft"}}}},"responses":{"200":{"description":"The prediction.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApprovalPrediction"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"}}}},"/v1/calls":{"get":{"operationId":"listCalls","tags":["Calls"],"summary":"List calls","description":"Inbound and human-outbound calls, newest first, with cursor pagination.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":100,"description":"Page size (1-200). Default 100."},"required":false,"description":"Page size (1-200). Default 100.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","description":"Only calls in this status."},"required":false,"description":"Only calls in this status.","name":"status","in":"query"},{"schema":{"type":"string","enum":["inbound","outbound"],"description":"Only `inbound` or only `outbound` calls."},"required":false,"description":"Only `inbound` or only `outbound` calls.","name":"direction","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of calls.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/calls/{id}":{"get":{"operationId":"getCall","tags":["Calls"],"summary":"Retrieve a call","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The call id.","example":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The call.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Call"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/calls/{id}/transfer":{"post":{"operationId":"transferCall","tags":["Calls"],"summary":"Transfer a call","description":"Hands an active, bridged call to another destination: one of your softphone devices (`deviceId`) or an external number (`to`). Provide exactly one. The response returns as soon as the transfer leg is dialed; the bridge completes asynchronously. `409 conflict` when the call is not currently connected or a transfer is already in flight.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The call id.","example":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string","format":"uuid","description":"One of your softphone device ids. Mutually exclusive with `to`."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"An external number (E.164). Mutually exclusive with `deviceId`."}}},"example":{"to":"+15555550150"}}}},"responses":{"200":{"description":"The transfer leg was dialed.","content":{"application/json":{"schema":{"type":"object","properties":{"transferredTo":{"type":"string","description":"The destination being dialed."}},"required":["transferredTo"],"example":{"transferredTo":"+15555550150"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/calls/{id}/recording":{"get":{"operationId":"getCallRecording","tags":["Calls"],"summary":"Download a call recording","description":"Redirects to the recorded audio. `404` until the recording has saved.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The call id.","example":"0c7f3a52-91ab-4d6e-8f10-23b4c5d6e7f8"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The audio, once the redirect is followed (most HTTP clients and `<audio>` tags do so automatically).","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}},"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"302":{"description":"Redirect to a fresh, short-lived signed URL for the call recording. Follow it immediately and never store it.","headers":{"Location":{"description":"The signed audio URL.","schema":{"type":"string","format":"uri"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/voicemails":{"get":{"operationId":"listVoicemails","tags":["Voicemails"],"summary":"List voicemails","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":100,"description":"Page size (1-200). Default 100."},"required":false,"description":"Page size (1-200). Default 100.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of voicemails.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoicemailPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/voicemails/{id}":{"get":{"operationId":"getVoicemail","tags":["Voicemails"],"summary":"Retrieve a voicemail","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The voicemail id.","example":"9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The voicemail.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Voicemail"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/voicemails/{id}/audio":{"get":{"operationId":"getVoicemailAudio","tags":["Voicemails"],"summary":"Download voicemail audio","description":"Redirects to the audio. `404` until the voicemail has saved.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The voicemail id.","example":"9d8c7b6a-5e4f-4a3b-9c2d-1e0f9a8b7c6d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The audio, once the redirect is followed (most HTTP clients and `<audio>` tags do so automatically).","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}},"audio/wav":{"schema":{"type":"string","format":"binary"}}}},"302":{"description":"Redirect to a fresh, short-lived signed URL for the voicemail audio. Follow it immediately and never store it.","headers":{"Location":{"description":"The signed audio URL.","schema":{"type":"string","format":"uri"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webhooks":{"get":{"operationId":"listWebhooks","tags":["Webhooks"],"summary":"List webhook endpoints","description":"Secrets are write-once and never listed.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your endpoints.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointPage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createWebhook","tags":["Webhooks"],"summary":"Create a webhook endpoint","description":"Registers an endpoint to receive events (see the Webhooks section of this document for the events, payloads and signature scheme). The response includes the signing secret exactly once.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"The HTTPS URL to POST events to."},"events":{"type":["array","null"],"items":{"type":"string"},"minItems":1,"maxItems":64,"description":"Event types to deliver, or `[\"*\"]` / null for every event. Valid types: `message.received`, `message.status`, `call.ringing`, `call.completed`, `call.missed`, `call.ivr.key_pressed`, `call.transcript`, `call.transcript.delta`, `voicemail.received`, `billing.wallet.credited`, `billing.wallet.low_balance`, `billing.subscription.updated`, `lead.captured`, `webhook_endpoint.disabled`, `domain.verified`, `domain.failed`, `domain.degraded`, `domain.expired`, `email.sent`, `email.delivered`, `email.deferred`, `email.bounced`, `email.failed`, `email.opened`, `email.clicked`, `email.complained`, `email.unsubscribed`."}},"required":["url"]},"example":{"url":"https://example.com/webhooks/mittis","events":["message.received","message.status"]}}}},"responses":{"201":{"description":"The endpoint, with its secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreated"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/webhooks/{id}":{"get":{"operationId":"getWebhook","tags":["Webhooks"],"summary":"Retrieve a webhook endpoint","description":"The signing secret is write-once and never returned.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateWebhook","tags":["Webhooks"],"summary":"Update a webhook endpoint","description":"Provide at least one of `url`, `events`, `enabled`. The secret cannot be changed.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"New destination URL."},"events":{"type":["array","null"],"items":{"type":"string"},"minItems":1,"maxItems":64,"description":"Event types to deliver, or `[\"*\"]` / null for every event. Valid types: `message.received`, `message.status`, `call.ringing`, `call.completed`, `call.missed`, `call.ivr.key_pressed`, `call.transcript`, `call.transcript.delta`, `voicemail.received`, `billing.wallet.credited`, `billing.wallet.low_balance`, `billing.subscription.updated`, `lead.captured`, `webhook_endpoint.disabled`, `domain.verified`, `domain.failed`, `domain.degraded`, `domain.expired`, `email.sent`, `email.delivered`, `email.deferred`, `email.bounced`, `email.failed`, `email.opened`, `email.clicked`, `email.complained`, `email.unsubscribed`. Null (or `[\"*\"]`) means all events."},"enabled":{"type":"boolean","description":"Pause or resume delivery."}}},"example":{"enabled":false}}}},"responses":{"200":{"description":"The updated endpoint.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpoint"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteWebhook","tags":["Webhooks"],"summary":"Delete a webhook endpoint","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The endpoint was deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webhooks/{id}/deliveries":{"get":{"operationId":"listWebhookDeliveries","tags":["Webhooks"],"summary":"List webhook deliveries","description":"The delivery log for one endpoint: the last 7 days, newest first. Only durable events are logged; best-effort events such as `call.transcript.delta` are not.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"The `nextCursor` of the previous page (a delivery id)."},"required":false,"description":"The `nextCursor` of the previous page (a delivery id).","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Page size (1-200). Default 50."},"required":false,"description":"Page size (1-200). Default 50.","name":"limit","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of deliveries.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webhooks/{id}/deliveries/{deliveryId}":{"get":{"operationId":"getWebhookDelivery","tags":["Webhooks"],"summary":"Retrieve a webhook delivery","description":"One delivery with its `payload` (the event body that is sent), plus the last response status and error code. Deliveries are kept for 7 days.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"The delivery id.","example":"f0e1d2c3-b4a5-4968-8776-655443322110"},"required":true,"name":"deliveryId","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The delivery.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDeliveryDetail"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webhooks/{id}/deliveries/{deliveryId}/retry":{"post":{"operationId":"retryWebhookDelivery","tags":["Webhooks"],"summary":"Redeliver an event","description":"Makes one immediate attempt to redeliver that delivery’s original event body (with a fresh signature) and returns the delivery’s new state. `409 conflict` if the endpoint is disabled or the delivery is already being attempted.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"The delivery id.","example":"f0e1d2c3-b4a5-4968-8776-655443322110"},"required":true,"name":"deliveryId","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The delivery after the attempt.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookDelivery"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/webhooks/{id}/rotate-secret":{"post":{"operationId":"rotateWebhookSecret","tags":["Webhooks"],"summary":"Rotate the signing secret","description":"Generates a new signing secret and returns it exactly once; it is never shown again by any read. The old secret stops being used immediately: every delivery attempt from now on, including retries of deliveries already queued, is signed with the new secret. Update your receiver first or accept a short window of signature failures. Requires an admin when called with a signed-in session.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The endpoint, with its new secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointCreated"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webhooks/{id}/test":{"post":{"operationId":"sendTestWebhook","tags":["Webhooks"],"summary":"Send a test event","description":"Delivers a sample `message.received` event to the endpoint (one attempt, no retries) so you can verify the signature and envelope before real traffic. The event also appears in `GET /v1/events`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The webhook endpoint id.","example":"1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The receiver’s answer. `status` is absent when the receiver was unreachable.","content":{"application/json":{"schema":{"type":"object","properties":{"delivered":{"type":"boolean","description":"True when the receiver answered 2xx."},"status":{"type":"integer","description":"The receiver’s HTTP status, when it answered."}},"required":["delivered"],"example":{"delivered":true,"status":200}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/keys":{"get":{"operationId":"listApiKeys","tags":["API keys"],"summary":"List API keys","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your keys, including revoked ones.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyPage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createApiKey","tags":["API keys"],"summary":"Create an API key","description":"Mints a new key. The secret is in the response only. A `test` key can only create `test` keys (`403 forbidden` otherwise), so a leaked test key can never mint a live one.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"A label to recognise the key by."},"mode":{"type":"string","enum":["live","test"],"default":"live","description":"`live` (default) or `test`."}},"required":["name"]},"example":{"name":"Production server","mode":"live"}}}},"responses":{"201":{"description":"The key and its secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/keys/{id}/revoke":{"post":{"operationId":"revokeApiKey","tags":["API keys"],"summary":"Revoke an API key","description":"Immediately stops the key from authenticating. Cannot be undone.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The key id."},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The key was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/events":{"get":{"operationId":"listEvents","tags":["Events"],"summary":"Poll the event feed","description":"A durable, ordered feed of the same events webhooks deliver, for consumers that cannot receive inbound HTTP (this powers `mittis listen`). Poll forward: start with `after=now` to get a cursor without any events, then pass each response’s `cursor` as `after`. Events are returned oldest first by default (`order=asc`); pass `order=desc` for newest first, paging back with `before` (the response’s `nextCursor`). An unknown `after` starts from the beginning of retention. Event ids match the `id` of the delivered webhook (`evt_<id>`).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"anyOf":[{"type":"string","enum":["now"]},{"type":"string","format":"uuid"},{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"}],"description":"Resume after this event: an event id (uuid), a delivered webhook `id` (`evt_…`), or the literal `now` to bootstrap a listener."},"required":false,"description":"Resume after this event: an event id (uuid), a delivered webhook `id` (`evt_…`), or the literal `now` to bootstrap a listener.","name":"after","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":100,"description":"Page size (1-200). Default 100."},"required":false,"description":"Page size (1-200). Default 100.","name":"limit","in":"query"},{"schema":{"type":"string","description":"Comma-separated event types to include, e.g. `message.received,call.completed`."},"required":false,"description":"Comma-separated event types to include, e.g. `message.received,call.completed`.","name":"types","in":"query"},{"schema":{"type":"string","enum":["asc","desc"],"default":"asc","description":"`asc` (default): oldest first, resume with `after`. `desc`: newest first, page backwards with `before`."},"required":false,"description":"`asc` (default): oldest first, resume with `after`. `desc`: newest first, page backwards with `before`.","name":"order","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"}],"description":"With `order=desc`: only events older than this event id (uuid or `evt_…`). Not valid with `order=asc`."},"required":false,"description":"With `order=desc`: only events older than this event id (uuid or `evt_…`). Not valid with `order=asc`.","name":"before","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Events after the cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantEventFeed"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/events/{id}":{"get":{"operationId":"getEvent","tags":["Events"],"summary":"Retrieve an event","description":"One event from the feed, by its feed id (uuid) or the delivered webhook’s `evt_…` id. `404` if it does not exist for your account.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","pattern":"^evt_[0-9a-f-]{36}$"}],"description":"The event id: a uuid or `evt_<uuid>`.","example":"6b8c2a14-3d5e-4f70-9a1b-2c3d4e5f6a7b"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The event.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantEvent"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/usage":{"get":{"operationId":"getUsage","tags":["Usage"],"summary":"Current-period usage","description":"Message, segment and email-recipient counts and your billed spend for the current period, with your spend limit if one is set. All money is integer cents.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Usage for the current period.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/billing":{"get":{"operationId":"getBilling","tags":["Billing"],"summary":"Billing snapshot","description":"Subscription and prepaid-wallet state for your account.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The billing snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Billing"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"operationId":"updateBilling","tags":["Billing"],"summary":"Update billing settings","description":"Updates the wallet auto-recharge policy and returns the new snapshot. Fields you omit are unchanged.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autoRecharge":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Recharge automatically when the balance drops below `thresholdCents`."},"thresholdCents":{"type":"integer","minimum":0,"maximum":1000000,"description":"Recharge when the balance falls below this many cents (0-1,000,000)."},"amountCents":{"type":"integer","minimum":500,"maximum":1000000,"description":"How many cents to add each time (500-1,000,000)."}},"required":["enabled","thresholdCents","amountCents"]}}},"example":{"autoRecharge":{"enabled":true,"thresholdCents":1000,"amountCents":5000}}}}},"responses":{"200":{"description":"The updated billing snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Billing"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/billing/portal-session":{"post":{"operationId":"createBillingPortalSession","tags":["Billing"],"summary":"Open the billing portal","description":"Returns a hosted page where the user manages their card and invoices.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"returnUrl":{"type":"string","format":"uri","description":"Where to send the user afterwards. Must be an absolute http(s) URL."}},"required":["returnUrl"]},"example":{"returnUrl":"https://example.com/settings/billing"}}}},"responses":{"200":{"description":"The portal session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/billing/subscribe-session":{"post":{"operationId":"createSubscribeSession","tags":["Billing"],"summary":"Start a subscription checkout","description":"Returns a hosted checkout page to subscribe to your plan. The price follows your own tier. Subscribing makes the monthly fee charge the card instead of the wallet, leaving the balance for usage. `409 conflict` when your plan is not subscribable.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"returnUrl":{"type":"string","format":"uri","description":"Where to send the user afterwards. Must be an absolute http(s) URL."}},"required":["returnUrl"]},"example":{"returnUrl":"https://example.com/settings/billing"}}}},"responses":{"200":{"description":"The checkout session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/wallet/topup-session":{"post":{"operationId":"createWalletTopupSession","tags":["Billing"],"summary":"Start a wallet top-up checkout","description":"Returns a hosted checkout page to add funds to the prepaid wallet. The balance updates when payment completes (a `billing.wallet.credited` event follows).","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountCents":{"type":"integer","minimum":500,"maximum":500000,"description":"Amount to add in cents (500-500,000)."},"returnUrl":{"type":"string","format":"uri","description":"Where to send the user afterwards. Must be an absolute http(s) URL."}},"required":["amountCents","returnUrl"]},"example":{"amountCents":5000,"returnUrl":"https://example.com/settings/billing"}}}},"responses":{"200":{"description":"The checkout session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/wallet/transactions":{"get":{"operationId":"listWalletTransactions","tags":["Billing"],"summary":"List wallet transactions","description":"The prepaid wallet ledger, newest first, with cursor pagination.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Legacy alias of `cursor`."},"required":false,"description":"Legacy alias of `cursor`.","name":"after","in":"query"},{"schema":{"type":"string","format":"uuid","description":"The `nextCursor` of the previous page (a transaction id)."},"required":false,"description":"The `nextCursor` of the previous page (a transaction id).","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Page size (1-100). Default 25."},"required":false,"description":"Page size (1-100). Default 25.","name":"limit","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of ledger rows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletTransactionPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/agency/billing":{"get":{"operationId":"getAgencyBilling","tags":["Agency"],"summary":"Agency billing snapshot","description":"Subscription and prepaid-wallet state for the agency’s own account.","security":[{"ApiKey":[]}],"responses":{"200":{"description":"The billing snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Billing"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"patch":{"operationId":"updateAgencyBilling","tags":["Agency"],"summary":"Update agency billing settings","description":"Updates the wallet auto-recharge policy and returns the new snapshot. Fields you omit are unchanged.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"autoRecharge":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Recharge automatically when the balance drops below `thresholdCents`."},"thresholdCents":{"type":"integer","minimum":0,"maximum":1000000,"description":"Recharge when the balance falls below this many cents (0-1,000,000)."},"amountCents":{"type":"integer","minimum":500,"maximum":1000000,"description":"How many cents to add each time (500-1,000,000)."}},"required":["enabled","thresholdCents","amountCents"]}}},"example":{"autoRecharge":{"enabled":true,"thresholdCents":1000,"amountCents":5000}}}}},"responses":{"200":{"description":"The updated billing snapshot.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Billing"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/agency/billing/portal-session":{"post":{"operationId":"createAgencyBillingPortalSession","tags":["Agency"],"summary":"Open the billing portal","description":"Returns a hosted page where the user manages their card and invoices.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"returnUrl":{"type":"string","format":"uri","description":"Where to send the user afterwards. Must be an absolute http(s) URL."}},"required":["returnUrl"]},"example":{"returnUrl":"https://example.com/settings/billing"}}}},"responses":{"200":{"description":"The portal session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/agency/billing/subscribe-session":{"post":{"operationId":"createAgencySubscribeSession","tags":["Agency"],"summary":"Start a subscription checkout","description":"Returns a hosted checkout page to subscribe to your plan. The price follows your own tier. Subscribing makes the monthly fee charge the card instead of the wallet, leaving the balance for usage. `409 conflict` when your plan is not subscribable.","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"returnUrl":{"type":"string","format":"uri","description":"Where to send the user afterwards. Must be an absolute http(s) URL."}},"required":["returnUrl"]},"example":{"returnUrl":"https://example.com/settings/billing"}}}},"responses":{"200":{"description":"The checkout session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/agency/wallet/topup-session":{"post":{"operationId":"createAgencyWalletTopupSession","tags":["Agency"],"summary":"Start a wallet top-up checkout","description":"Returns a hosted checkout page to add funds to the prepaid wallet. The balance updates when payment completes (a `billing.wallet.credited` event follows).","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amountCents":{"type":"integer","minimum":500,"maximum":500000,"description":"Amount to add in cents (500-500,000)."},"returnUrl":{"type":"string","format":"uri","description":"Where to send the user afterwards. Must be an absolute http(s) URL."}},"required":["amountCents","returnUrl"]},"example":{"amountCents":5000,"returnUrl":"https://example.com/settings/billing"}}}},"responses":{"200":{"description":"The checkout session.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutSession"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/agency/wallet/transactions":{"get":{"operationId":"listAgencyWalletTransactions","tags":["Agency"],"summary":"List wallet transactions","description":"The prepaid wallet ledger, newest first, with cursor pagination.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"Legacy alias of `cursor`."},"required":false,"description":"Legacy alias of `cursor`.","name":"after","in":"query"},{"schema":{"type":"string","format":"uuid","description":"The `nextCursor` of the previous page (a transaction id)."},"required":false,"description":"The `nextCursor` of the previous page (a transaction id).","name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":100,"description":"Page size (1-100). Default 25."},"required":false,"description":"Page size (1-100). Default 25.","name":"limit","in":"query"}],"responses":{"200":{"description":"A page of ledger rows.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletTransactionPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/agency/usage":{"get":{"operationId":"getAgencyUsage","tags":["Agency"],"summary":"Usage across all sub-accounts","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","description":"The period as `YYYY-MM`. Defaults to the current month."},"required":false,"description":"The period as `YYYY-MM`. Defaults to the current month.","name":"period","in":"query"}],"responses":{"200":{"description":"The usage rollup.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyUsageRollup"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/agency/statement":{"get":{"operationId":"getAgencyStatement","tags":["Agency"],"summary":"Agency statement","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","description":"The period as `YYYY-MM`. Defaults to the current month."},"required":false,"description":"The period as `YYYY-MM`. Defaults to the current month.","name":"period","in":"query"}],"responses":{"200":{"description":"The statement.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyStatement"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/agency/wallet/reconciliation":{"get":{"operationId":"getAgencyWalletReconciliation","tags":["Agency"],"summary":"Reconcile the wallet","description":"Never cached (`Cache-Control: private, no-store`).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}$","description":"The period as `YYYY-MM`. Defaults to the current month."},"required":false,"description":"The period as `YYYY-MM`. Defaults to the current month.","name":"period","in":"query"}],"responses":{"200":{"description":"The reconciliation report.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletReconciliation"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/agency/numbers":{"get":{"operationId":"listAgencyNumbers","tags":["Agency"],"summary":"List the number fleet","description":"Every number owned by the agency or any of its sub-accounts, with its monthly rental and a routing summary.","security":[{"ApiKey":[]}],"responses":{"200":{"description":"The fleet.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgencyNumberPage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/ports/check":{"post":{"operationId":"checkPortability","tags":["Ports"],"summary":"Check portability","description":"Read-only check of whether numbers can be ported, before opening a request. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumbers":{"type":"array","items":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"},"minItems":1,"maxItems":100,"description":"The numbers to check (1-100, E.164)."}},"required":["phoneNumbers"]},"example":{"phoneNumbers":["+15555550177"]}}}},"responses":{"200":{"description":"One result per number.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortabilityResultPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/PortabilityResult"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/ports":{"get":{"operationId":"listPorts","tags":["Ports"],"summary":"List port requests","description":"Newest first. Send `?format=array` or `Accept: application/vnd.mittis.list+json` to receive a bare top-level array instead of the envelope.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":100,"description":"Page size (1-200). Default 100."},"required":false,"description":"Page size (1-200). Default 100.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["array"],"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope."},"required":false,"description":"Pass `array` to receive a bare top-level array instead of the `{ data }` envelope.","name":"format","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your port requests.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortPage"}},"application/vnd.mittis.list+json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Port"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createPort","tags":["Ports"],"summary":"Create a port request","description":"Opens a port request as a draft. The flow is: check portability, create, fetch the letter of authorization (`GET /v1/ports/{id}/loa`), sign it, upload the signed LOA and the latest invoice (`POST /v1/ports/{id}/documents`), then submit. Use `Idempotency-Key` to make retries safe: a repeated key returns the original request with `Idempotent-Replayed: true`. A test key uses a simulated carrier and never starts a real port.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"},{"$ref":"#/components/parameters/IdempotencyKeyHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortCreateRequest"}}}},"responses":{"201":{"description":"The draft port request.","headers":{"Idempotent-Replayed":{"description":"`true` when this is the original request returned for a repeated `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/ports/{id}":{"get":{"operationId":"getPort","tags":["Ports"],"summary":"Retrieve a port request","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The port request id.","example":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The request with its numbers, documents and timeline.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updatePort","tags":["Ports"],"summary":"Update a port request","description":"Corrects fields, typically after a carrier rejection (`status: rejected` with a `blocker`), and then you submit again. Rejected with `409 conflict` once the request can no longer change.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The port request id.","example":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortUpdateRequest"}}}},"responses":{"200":{"description":"The updated request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/ports/{id}/submit":{"post":{"operationId":"submitPort","tags":["Ports"],"summary":"Submit a port request","description":"Submits (or resubmits after a rejection) to the losing carrier. A signed LOA must be on file (`409 conflict` otherwise).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The port request id.","example":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The request with its new status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/ports/{id}/cancel":{"post":{"operationId":"cancelPort","tags":["Ports"],"summary":"Cancel a port request","description":"Asks to cancel. The status becomes `cancel_requested` until the carrier confirms; it can still decline.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The port request id.","example":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The request with its new status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PortResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/ports/{id}/loa":{"get":{"operationId":"getPortLoa","tags":["Ports"],"summary":"Download the letter of authorization","description":"The LOA as a PDF to sign. Returns `409 conflict` until the request has a carrier order (update it with PATCH to create one).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The port request id.","example":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The letter of authorization.","headers":{"Content-Disposition":{"description":"Always `attachment; filename=\"letter-of-authorization.pdf\"`.","schema":{"type":"string"}},"Cache-Control":{"description":"Always `no-store`.","schema":{"type":"string"}}},"content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/ports/{id}/documents":{"post":{"operationId":"uploadPortDocument","tags":["Ports"],"summary":"Upload a port document","description":"Attaches a document as `multipart/form-data` with a `kind` field and a `file` part (PDF, JPG or PNG, up to 10 MB).","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The port request id.","example":"c4d5e6f7-a8b9-4c0d-8e1f-2a3b4c5d6e7f"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"kind":{"type":"string","enum":["loa","invoice","other"],"description":"`loa` (signed letter of authorization), `invoice` (latest invoice from the losing carrier) or `other`."},"file":{"type":"string","description":"PDF, JPG or PNG, up to 10 MB.","format":"binary"}},"required":["kind","file"]}}}},"responses":{"201":{"description":"The stored document.","content":{"application/json":{"schema":{"type":"object","properties":{"document":{"$ref":"#/components/schemas/PortDocument"}},"required":["document"],"description":"The stored document."}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/domains":{"post":{"operationId":"createDomain","tags":["Email domains"],"summary":"Add a sending domain","description":"Registers a domain you own for sending email and returns the DNS records to publish. The domain starts `pending`; publish the records, then call `POST /v1/domains/{id}/verify`. Public mailbox providers (like gmail.com), disposable domains, IP addresses and single-label hosts are rejected. A domain can belong to one account only. Unverified domains are released after 7 days (a `domain.expired` webhook fires); a domain that was ever verified is never released automatically. Requires email to be enabled for the account.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","minLength":1,"maxLength":253,"description":"The domain to send from, like `example.com` or `mail.example.com`."}},"required":["domain"]},"example":{"domain":"example.com"}}}},"responses":{"201":{"description":"The domain, pending verification.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}},"get":{"operationId":"listDomains","tags":["Email domains"],"summary":"List sending domains","description":"Newest first. Returned whole (`hasMore` is always false).","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your sending domains.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainPage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/domains/{id}":{"get":{"operationId":"getDomain","tags":["Email domains"],"summary":"Retrieve a sending domain","description":"Returns the domain with the status of each DNS record. If the last check is older than a minute it is refreshed first.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The domain id.","example":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The domain.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"operationId":"deleteDomain","tags":["Email domains"],"summary":"Delete a sending domain","description":"Removes the domain. It can no longer send; you can add it again later.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The domain id.","example":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"204":{"description":"Deleted."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/domains/{id}/verify":{"post":{"operationId":"verifyDomain","tags":["Email domains"],"summary":"Verify a sending domain","description":"Checks your DNS now. A `200` does not mean the domain is verified: read `status` (`verified`, `pending` while records propagate, or `failed`). Pending domains are also re-checked automatically for 72 hours, and a `domain.verified` webhook fires when the status changes.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The domain id.","example":"7b1c9d2e-3f4a-4b5c-8d6e-9f0a1b2c3d4e"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The domain after the check.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/emails":{"post":{"operationId":"sendEmail","tags":["Email"],"summary":"Send an email","description":"Sends an email from a verified [sending domain](#tag/Email-domains). The email is queued and the response returns immediately; it starts `queued`. Provide `html`, `text`, or both. Up to 50 recipients in total across `to`, `cc` and `bcc`; each accepted recipient is billed, and recipients we skip because of an earlier bounce, complaint or unsubscribe (`suppressed`) are not. If every recipient is suppressed the email is returned with status `failed` and nothing is billed. Requests are rate limited per account (`429 rate_limited`). Use `Idempotency-Key` to make retries safe: a repeated key returns the original email with `Idempotent-Replayed: true` and does not send again. `sk_test_` keys send nothing and bill nothing. Sends where every recipient is a reserved sandbox test address (such as `delivered@`, `hard-bounce@` or `complaint@`) are sandboxed: not delivered and not billed, but they produce real lifecycle webhooks; mixing them with real recipients is rejected with `400 validation_error`. Attachments, templates, scheduling and batch sending are not available yet.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"},{"$ref":"#/components/parameters/IdempotencyKeyHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendEmailRequest"}}}},"responses":{"201":{"description":"The email was accepted.","headers":{"Idempotent-Replayed":{"description":"`true` when this is the original email returned for a repeated `Idempotency-Key`.","schema":{"type":"string","enum":["true"]}},"X-Mittis-Budget-Warning":{"description":"`true` when this send pushed monthly spend past the soft threshold of your spend limit.","schema":{"type":"string","enum":["true"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Email"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"502":{"$ref":"#/components/responses/ProviderError"}}},"get":{"operationId":"listEmails","tags":["Email"],"summary":"List emails","description":"Emails you sent, newest first, with cursor pagination. Filter by `status`, by a primary recipient with `to`, or by `tag`. Message bodies are not included in the list; retrieve one email for its `html` and `text`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Page size (1-200). Default 50."},"required":false,"description":"Page size (1-200). Default 50.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","enum":["queued","sent","delivered","partially_delivered","bounced","failed"],"description":"Only emails in this state."},"required":false,"description":"Only emails in this state.","name":"status","in":"query"},{"schema":{"type":"string","maxLength":320,"description":"Only emails with this address in `to`."},"required":false,"description":"Only emails with this address in `to`.","name":"to","in":"query"},{"schema":{"type":"string","maxLength":64,"description":"Only emails carrying exactly this tag (one of the `tags` you sent)."},"required":false,"description":"Only emails carrying exactly this tag (one of the `tags` you sent).","name":"tag","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of emails.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/emails/{id}":{"get":{"operationId":"getEmail","tags":["Email"],"summary":"Retrieve an email","description":"Returns the email with its stored `html` and `text` bodies, `recipientStatuses` and its newest delivery events. `status` rolls the recipients up: `delivered` when every accepted recipient was delivered, `partially_delivered` when some were and others bounced or failed, `bounced` or `failed` when none were.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The email id.","example":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The email.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/emails/{id}/events":{"get":{"operationId":"listEmailEvents","tags":["Email"],"summary":"List an email's delivery events","description":"Every delivery and engagement event for the email, newest first, with cursor pagination. `opened` and `clicked` only appear when open/click tracking is enabled for your account.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","description":"The email id.","example":"3c8f1d62-7a4e-4b9d-9e21-5f6a7b8c9d0e"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Page size (1-200). Default 50."},"required":false,"description":"Page size (1-200). Default 50.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of events.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailEventPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/email-suppressions":{"get":{"operationId":"listEmailSuppressions","tags":["Email"],"summary":"List suppressed email addresses","description":"Addresses we will not send to for your account. Hard bounces, spam complaints and unsubscribes are added automatically. Filter to one address with `address`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50,"description":"Page size (1-200). Default 50."},"required":false,"description":"Page size (1-200). Default 50.","name":"limit","in":"query"},{"schema":{"type":"string","minLength":1,"maxLength":512,"description":"The `nextCursor` of the previous page."},"required":false,"description":"The `nextCursor` of the previous page.","name":"cursor","in":"query"},{"schema":{"type":"string","maxLength":320,"description":"Only this address."},"required":false,"description":"Only this address.","name":"address","in":"query"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"A page of suppressions.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSuppressionPage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}},"post":{"operationId":"createEmailSuppression","tags":["Email"],"summary":"Suppress an email address","description":"Stop sending to an address. If it is already suppressed the existing record is returned unchanged.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateEmailSuppressionRequest"}}}},"responses":{"201":{"description":"The suppression.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSuppression"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/email-suppressions/{address}":{"delete":{"operationId":"deleteEmailSuppression","tags":["Email"],"summary":"Remove an email suppression","description":"Lets you send to the address again. Only `manual` and `unsubscribe` suppressions can be removed; addresses that hard-bounced or complained return `409 conflict`.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","minLength":3,"maxLength":320,"description":"The suppressed address (URL-encode the `@`).","example":"optout@example.com"},"required":true,"name":"address","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"204":{"description":"Removed."},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}}}},"/v1/webrtc/devices":{"post":{"operationId":"createSoftphoneDevice","tags":["Softphone"],"summary":"Provision a softphone device","description":"Provisions (or returns the existing) softphone endpoint for one of your users. Idempotent on (`userId`, `label`): repeating the request returns the same device (`200`) without another carrier call; the first call returns `201`.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","minLength":1,"maxLength":200,"description":"Your own user identifier."},"label":{"type":"string","minLength":1,"maxLength":80,"default":"softphone","description":"Device label (default `softphone`). Use distinct labels for one user’s several devices."},"wakeMode":{"type":"string","enum":["presence","push"],"description":"`presence` (default, the web softphone) is dialed only while online. `push` (the native mobile app) is dialed even while offline, waking the phone with a VoIP push."}},"required":["userId"]},"example":{"userId":"user_123","label":"softphone"}}}},"responses":{"200":{"description":"The device already existed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftphoneDevice"}}}},"201":{"description":"The device was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftphoneDevice"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"502":{"$ref":"#/components/responses/ProviderError"}}},"get":{"operationId":"listSoftphoneDevices","tags":["Softphone"],"summary":"List softphone devices","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"Your devices with presence.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftphoneDeviceList"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/webrtc/devices/{id}":{"delete":{"operationId":"deleteSoftphoneDevice","tags":["Softphone"],"summary":"Delete a softphone device","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The softphone device id.","example":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"204":{"description":"The device was deleted."},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webrtc/devices/{id}/token":{"post":{"operationId":"createSoftphoneToken","tags":["Softphone"],"summary":"Mint a login token","description":"A short-lived token the browser uses to register the device. Mint a fresh one when registration fails.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The softphone device id.","example":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftphoneToken"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/webrtc/devices/{id}/credential":{"post":{"operationId":"getSoftphoneCredential","tags":["Softphone"],"summary":"Get a long-lived SIP credential","description":"For native VoIP-push apps that must re-register at call time, hours after the app last opened. Returns a secret password: call it only with your server-side key and never log the response.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The softphone device id.","example":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The credential.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftphoneCredential"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/webrtc/devices/{id}/detach":{"post":{"operationId":"detachSoftphoneDevice","tags":["Softphone"],"summary":"Sign a device out","description":"Detaches the device from any live session so calls stop ringing it. A `push` device is otherwise dialed even while offline, so call this on sign-out. The device and its route destinations are kept; the next login re-attaches it automatically.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The softphone device id.","example":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"responses":{"200":{"description":"The device was detached.","content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string"},"detached":{"type":"boolean","enum":[true]}},"required":["deviceId","detached"],"example":{"deviceId":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6","detached":true}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webrtc/devices/{id}/presence":{"post":{"operationId":"setSoftphonePresence","tags":["Softphone"],"summary":"Set device presence","description":"Heartbeat from the softphone: `online` while registered, `offline` when it goes away. An `online` heartbeat goes stale after a short TTL, so send it periodically.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The softphone device id.","example":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6"},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","enum":["online","offline"],"description":"`online` or `offline`."}},"required":["status"]},"example":{"status":"online"}}}},"responses":{"200":{"description":"The recorded presence.","content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string"},"status":{"type":"string","enum":["online","offline"]},"lastSeenAt":{"type":"string","description":"ISO 8601."}},"required":["deviceId","status","lastSeenAt"],"example":{"deviceId":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6","status":"online","lastSeenAt":"2026-07-01T15:00:00.000Z"}}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/webrtc/calls":{"post":{"operationId":"createSoftphoneCall","tags":["Softphone"],"summary":"Place an outbound call","description":"Places a human outbound call from a softphone. Mittis dials the device’s own leg, the device auto-answers, then Mittis dials the callee and bridges the two; the browser never originates a call itself, which prevents caller-id spoofing and keeps metering and webhooks intact. `from` must be one of your own voice numbers (`403 forbidden` otherwise) and defaults to your first voice-capable number. Set `agentNumber` to ring a rep’s own phone instead of the browser.","security":[{"ApiKey":[]}],"parameters":[{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"deviceId":{"type":"string","format":"uuid","description":"The softphone device placing the call."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"The number to call (E.164)."},"from":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Caller id: one of your own voice numbers. Defaults to your first voice-capable number."},"agentNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Ring this number (E.164) as the agent leg instead of the browser, then bridge the callee. Useful where in-browser calling is unreliable (e.g. iOS Safari)."}},"required":["deviceId","to"]},"example":{"deviceId":"d1e2f3a4-b5c6-4d7e-8f90-a1b2c3d4e5f6","to":"+15555550142"}}}},"responses":{"201":{"description":"The call was started.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoftphoneCall"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/webrtc/calls/{id}/cancel":{"post":{"operationId":"cancelSoftphoneCall","tags":["Softphone"],"summary":"Cancel an outbound call","description":"Hangs up an outbound call that has not been answered yet. `userId` must be the user who placed it.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The call id returned by `POST /v1/webrtc/calls`."},"required":true,"name":"id","in":"path"},{"$ref":"#/components/parameters/SubaccountHeader"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","minLength":1,"maxLength":256,"description":"The user who placed the call."}},"required":["userId"]},"example":{"userId":"user_123"}}}},"responses":{"200":{"description":"The call was cancelled.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"502":{"$ref":"#/components/responses/ProviderError"}}}},"/v1/subaccounts":{"post":{"operationId":"createSubaccount","tags":["Sub-accounts"],"summary":"Create a sub-account","description":"Provisions a child account with its first API key (and optionally a webhook endpoint). Idempotent on `slug`: repeating it for your own sub-account returns `200` with `alreadyProvisioned: true`; a slug owned by anyone else is `409 conflict`. A test-mode agency key can only create test sub-accounts. Requires the agency credential directly (not `Mittis-Subaccount`).","security":[{"ApiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Display name (max 120 characters)."},"slug":{"type":"string","minLength":3,"maxLength":64,"pattern":"^[a-z0-9][a-z0-9-]*$","description":"Unique id, 3-64 characters: lowercase letters, digits and hyphens."},"mode":{"type":"string","enum":["live","test"],"default":"live","description":"Mode of the first key: `live` (default) or `test`."},"webhookUrl":{"type":"string","format":"uri","description":"Optional URL to register as the sub-account’s first webhook endpoint."}},"required":["name","slug"]},"example":{"name":"Acme Plumbing","slug":"acme-plumbing","mode":"live"}}}},"responses":{"200":{"description":"A sub-account with that slug already exists under your agency.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubaccountProvisioned"}}}},"201":{"description":"The sub-account was created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubaccountProvisioned"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"}}},"get":{"operationId":"listSubaccounts","tags":["Sub-accounts"],"summary":"List sub-accounts","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Your sub-accounts, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubaccountPage"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/v1/subaccounts/{id}":{"get":{"operationId":"getSubaccount","tags":["Sub-accounts"],"summary":"Retrieve a sub-account","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The sub-account id.","example":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"The sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubaccountDetail"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"operationId":"updateSubaccount","tags":["Sub-accounts"],"summary":"Update a sub-account","description":"Rename it and/or switch texting, calling or email on or off. Provide at least one field.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The sub-account id.","example":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"New display name."},"smsEnabled":{"type":"boolean","description":"Allow or block texting."},"voiceEnabled":{"type":"boolean","description":"Allow or block calling."},"emailEnabled":{"type":"boolean","description":"Allow or block email (sending domains and sending)."}}},"example":{"smsEnabled":false}}}},"responses":{"200":{"description":"The updated sub-account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubaccountResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/subaccounts/{id}/keys":{"post":{"operationId":"createSubaccountKey","tags":["Sub-accounts"],"summary":"Create a sub-account API key","description":"Mints a key for the sub-account. The secret is in the response only.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The sub-account id.","example":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"A label to recognise the key by."},"mode":{"type":"string","enum":["live","test"],"default":"live","description":"`live` (default) or `test`. A test-mode agency key can only create test keys."}},"required":["name"]},"example":{"name":"Production server"}}}},"responses":{"201":{"description":"The key and its secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/subaccounts/{id}/keys/{keyId}/revoke":{"post":{"operationId":"revokeSubaccountKey","tags":["Sub-accounts"],"summary":"Revoke a sub-account API key","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The sub-account id.","example":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid","description":"The key id."},"required":true,"name":"keyId","in":"path"}],"responses":{"200":{"description":"The key was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OkResponse"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/v1/subaccounts/{id}/usage":{"get":{"operationId":"getSubaccountUsage","tags":["Sub-accounts"],"summary":"Sub-account usage","description":"Current-period usage for one sub-account.","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string","format":"uuid","description":"The sub-account id.","example":"5d0a6c0e-2f3b-4c55-9a52-1e9d3f3a7b11"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Usage for the current period.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Usage"}}}},"400":{"$ref":"#/components/responses/ValidationError"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}}},"webhooks":{"message.received":{"post":{"operationId":"webhook_message_received","tags":["Webhook events"],"summary":"Inbound message received","description":"Fired when a consumer texts one of your numbers. Fetch the full message with `GET /v1/messages/{messageId}`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageReceivedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"message.status":{"post":{"operationId":"webhook_message_status","tags":["Webhook events"],"summary":"Message delivery status changed","description":"Fired as an outbound message moves through its delivery states (`sent`, `delivered`, `failed`, `undelivered`). `reason` carries a sanitized failure reason when the carrier reported one.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageStatusEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.ringing":{"post":{"operationId":"webhook_call_ringing","tags":["Webhook events"],"summary":"Softphone devices are being dialed","description":"Fired per dialed softphone leg while an inbound call is ringing, so you can send a push notification that wakes a backgrounded app. Transient: it is attempted once and never retried, and the terminal `call.completed` / `call.missed` events remain the record. Never fired for SIP or PSTN-only routes.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallRingingEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.completed":{"post":{"operationId":"webhook_call_completed","tags":["Webhook events"],"summary":"A call was answered and ended","description":"Fired once when a call reaches its terminal state after being answered. `direction` is absent on older events; treat absence as `inbound`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallCompletedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.missed":{"post":{"operationId":"webhook_call_missed","tags":["Webhook events"],"summary":"A call ended without being answered","description":"Fired when a call ends unanswered. `outcome` is `voicemail` when a machine picked up and nobody pressed 1. `direction` is absent on older events; treat absence as `inbound`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallMissedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.ivr.key_pressed":{"post":{"operationId":"webhook_call_ivr_key_pressed","tags":["Webhook events"],"summary":"A caller pressed an IVR menu key","description":"Fired once per accepted keypress, before the key’s action runs. Invalid digits and timeouts never fire it.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallIvrKeyPressedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.transcript":{"post":{"operationId":"webhook_call_transcript","tags":["Webhook events"],"summary":"A recorded call has been transcribed","description":"Fired exactly once per recorded call, seconds to minutes after the call ends. A failed transcription still delivers, with `transcript: null` and `transcriptStatus: \"failed\"`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallTranscriptEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.transcript.delta":{"post":{"operationId":"webhook_call_transcript_delta","tags":["Webhook events"],"summary":"Live transcription of an in-progress call","description":"Streamed while a call is bridged, only on routes with `liveTranscription` enabled. Best effort: delivered once, never retried, and not ordered, so sort a burst by `at`. Interim results (`final: false`) are superseded by the next result for the same speaker; only `final: true` results are stable turns. The terminal `call.transcript` remains the durable record.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CallTranscriptDeltaEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"voicemail.received":{"post":{"operationId":"webhook_voicemail_received","tags":["Webhook events"],"summary":"A voicemail was captured and transcribed","description":"Fired once per captured voicemail, seconds to minutes after the `call.missed` with outcome `voicemail`. A failed transcription still delivers with `transcript: null`; the audio remains available at `recordingUrl`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoicemailReceivedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"billing.wallet.credited":{"post":{"operationId":"webhook_billing_wallet_credited","tags":["Webhook events"],"summary":"A wallet credit landed","description":"Fired to the paying account when a top-up or auto-recharge lands.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletCreditedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"billing.wallet.low_balance":{"post":{"operationId":"webhook_billing_wallet_low_balance","tags":["Webhook events"],"summary":"The wallet dropped below the recharge threshold","description":"Fired once per threshold crossing. `autoRechargeStarted` is false when there is no saved card or auto-recharge is disabled.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WalletLowBalanceEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"billing.subscription.updated":{"post":{"operationId":"webhook_billing_subscription_updated","tags":["Webhook events"],"summary":"The subscription status changed","description":"Fired when the subscription status changes (`active`, `past_due`, `canceled`, ...).\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionUpdatedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"lead.captured":{"post":{"operationId":"webhook_lead_captured","tags":["Webhook events"],"summary":"A brand’s hosted opt-in page was submitted","description":"Carries the captured lead so you can route it into your own CRM or automation. `consent` reflects the SMS-consent checkbox and `consentText` is the exact language shown, for your audit trail.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LeadCapturedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"webhook_endpoint.disabled":{"post":{"operationId":"webhook_webhook_endpoint_disabled","tags":["Webhook events"],"summary":"A webhook endpoint was automatically disabled","description":"Fired when an endpoint is disabled after sustained failure (at least 50 consecutive failed attempts, no success in 72 hours, and a failing streak at least 72 hours old). It is delivered to your other enabled endpoints that subscribe to it and appears in `GET /v1/events`, never to the disabled endpoint itself. Re-enable with `PATCH /v1/webhooks/{id}` and `{\"enabled\": true}`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEndpointDisabledEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"domain.verified":{"post":{"operationId":"webhook_domain_verified","tags":["Webhook events"],"summary":"A sending domain was verified","description":"Fired once when a sending domain becomes `verified` (including recovering from `degraded`). It can send from now on. Fetch it with `GET /v1/domains/{domainId}`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainVerifiedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"domain.failed":{"post":{"operationId":"webhook_domain_failed","tags":["Webhook events"],"summary":"A sending domain failed verification","description":"Fired when a required DNS record is missing or wrong and the domain moves to `failed`. Fix the records and call `POST /v1/domains/{domainId}/verify`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainFailedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"domain.degraded":{"post":{"operationId":"webhook_domain_degraded","tags":["Webhook events"],"summary":"A verified sending domain degraded","description":"Fired when a previously verified domain has a required record that now fails. It cannot send until you fix DNS; it returns to `verified` automatically once the records recover.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainDegradedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"domain.expired":{"post":{"operationId":"webhook_domain_expired","tags":["Webhook events"],"summary":"An unverified sending domain was released","description":"Fired when a domain that was never verified is released after 7 days. The domain no longer exists on your account; add it again to retry. Domains that were ever verified are never released automatically.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainExpiredEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.sent":{"post":{"operationId":"webhook_email_sent","tags":["Webhook events"],"summary":"An email left our servers for a recipient","description":"Fired per recipient when the email has been handed to the recipient's mail server queue. Every `email.*` event is per recipient: an email to three people fires up to three of each. `recipient` is omitted for a bcc recipient we cannot tell apart from the email's other bcc recipients.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailSentEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.delivered":{"post":{"operationId":"webhook_email_delivered","tags":["Webhook events"],"summary":"An email was delivered to a recipient","description":"Fired per recipient when the recipient's mail server accepted the message.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDeliveredEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.deferred":{"post":{"operationId":"webhook_email_deferred","tags":["Webhook events"],"summary":"Delivery to a recipient was delayed","description":"Fired when the recipient's server temporarily refused the message. We keep retrying; a later `email.delivered` or `email.bounced` settles it.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailDeferredEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.bounced":{"post":{"operationId":"webhook_email_bounced","tags":["Webhook events"],"summary":"An email bounced for a recipient","description":"Fired when delivery to a recipient permanently failed. `bounce.class` is `hard` (the address does not exist; the address is added to your suppression list), `soft`, `administrative`, `expired` or `unknown`.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailBouncedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.failed":{"post":{"operationId":"webhook_email_failed","tags":["Webhook events"],"summary":"An email failed for a recipient","description":"Fired when a message could not be sent to a recipient for a reason other than a bounce.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailFailedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.opened":{"post":{"operationId":"webhook_email_opened","tags":["Webhook events"],"summary":"A recipient opened an email","description":"Fired when a recipient opens the email. Only sent when open tracking is enabled for your account; opens are not fully reliable (mail apps can pre-load images).\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailOpenedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.clicked":{"post":{"operationId":"webhook_email_clicked","tags":["Webhook events"],"summary":"A recipient clicked a link","description":"Fired when a recipient clicks a tracked link; `url` is the link. Only sent when click tracking is enabled for your account.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailClickedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.complained":{"post":{"operationId":"webhook_email_complained","tags":["Webhook events"],"summary":"A recipient reported the email as spam","description":"Fired when a recipient marks the email as spam. The address is added to your suppression list and cannot be removed. Complaint rates above 0.2% pause your email sending.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailComplainedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"email.unsubscribed":{"post":{"operationId":"webhook_email_unsubscribed","tags":["Webhook events"],"summary":"A recipient unsubscribed","description":"Fired when a recipient unsubscribes (`method` is `link` or `one_click`). The address is added to your suppression list; you can remove it if they opt back in.\n\nDelivery is at-least-once: the same event can arrive more than once, so dedupe on `id`. Events are signed; verify the `X-Mittis-Signature` header before trusting the body.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"},{"schema":{"type":"string","description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature."},"required":true,"description":"The event id (`evt_…`), same as `id` in the body. Informational; not covered by the signature.","name":"mittis-event-id","in":"header"},{"schema":{"type":"string","description":"The event type, same as `type` in the body. Informational; not covered by the signature."},"required":true,"description":"The event type, same as `type` in the body. Informational; not covered by the signature.","name":"mittis-event-type","in":"header"},{"schema":{"type":"string","description":"`1` for the first attempt, `2` and up for retries. Informational."},"required":true,"description":"`1` for the first attempt, `2` and up for retries. Informational.","name":"mittis-delivery-attempt","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmailUnsubscribedEventDelivery"}}}},"responses":{"2XX":{"description":"Acknowledge with any 2xx status within 10 seconds. The response body is ignored. Anything else is a failure: timeouts, connection errors, `408`, `409`, `425`, `429` and `5xx` are retried with exponential backoff (about 30s, 2m, 10m, 30m, 1h, 3h, 6h, 12h; 9 attempts over roughly 23 hours, honoring `Retry-After`); other `4xx` and `3xx` responses are permanent failures and are not retried."}}}},"call.routing.decision":{"post":{"operationId":"webhook_call_routing_decision","tags":["Webhook events"],"summary":"Routing decision request (synchronous)","description":"Unlike the events above this is a synchronous request: when a number has a `decisionWebhook`, Mittis POSTs here as the call opens, before any greeting or ring, and waits up to `timeoutMs` (default 800 ms) for your answer. It is signed with the same `X-Mittis-Signature` scheme and your endpoint secret. It is strictly fail-open: a timeout, non-200 status or malformed body runs the number’s normal route, so it can never fail a call. It is sent once and never retried.","security":[],"parameters":[{"schema":{"type":"string","description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","example":"t=1783004982,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"},"required":true,"description":"Signature, `t=<unix seconds>,v1=<hex>`. `v1` is the lowercase hex HMAC-SHA256, keyed with your endpoint secret (`whsec_…`), of the string `\"<t>.<raw request body>\"`. Recompute it over the RAW body, compare in constant time, and reject timestamps older than 5 minutes (replay protection). The `parseWebhookEvent` helper in `@mittis/shared/webhooks` does all of this.","name":"x-mittis-signature","in":"header"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingDecisionRequest"}}}},"responses":{"200":{"description":"Your routing decision.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RoutingDecisionResponse"}}}}}}}}}