{"openapi":"3.1.0","info":{"title":"Pager API","version":"1.0.0","description":"The Pager API sends and receives SMS, manages the numbers that carry it, and\nrecords the consent that makes sending it lawful.\n\n## Authentication\n\nEvery endpoint except `/v1/health` requires an API key, presented as a bearer\ntoken:\n\n```\nAuthorization: Bearer pk_live_...\n```\n\nA key belongs to exactly one account and every request is scoped to it. A\nresource belonging to another account is reported as `404`, not `403`:\nanswering `403` would confirm the resource exists and let one tenant\nenumerate another's message and number ids by watching the status code.\n\nThe key is shown once, when it is issued, and stored only as a hash. A key that\nis lost cannot be recovered, only replaced.\n\n## Destinations and pricing\n\nPrice book `2026-09-11` covers the mainland United States, Canada,\nand Bulgaria. Other international destinations and separately priced NANP\nterritories remain unsupported.\n\n- payg: United States and Canada: $0.0148; Bulgaria: $0.1500 per SMS segment (USD).\n- growth: United States and Canada: $0.0133; Bulgaria: $0.1485 per SMS segment (USD).\n- committed: United States and Canada: $0.0113; Bulgaria: $0.1465 per SMS segment (USD).\n\nRates apply to every encoded SMS segment, including concatenated and UCS-2\nmessages. The response records `priceMicros` and `priceVersion`; retries\nretain the original charge. Bulgaria includes a published $0.1390 provider\nportion plus the tier fee, not an additional US carrier surcharge.\n\nBulgaria requires an explicitly configured international route for your\nassigned sending number. Keep that E.164 number in `from`; the carrier uses\nits configured branded sender instead. Message records retain your assigned\nnumber for ownership and filtering. Branded international SMS is one-way:\nrecipients cannot reply, and some carriers may rewrite the displayed sender.\nProvide a non-SMS opt-out/contact method rather than asking recipients to\nreply STOP. The hosted US 10DLC opt-in form is not an international signup form.\n\nAn unpriced destination or an unconfigured international sender is refused\nwith `403 destination_not_supported` before billing or queueing. Account\nownership, sandbox verification, consent, balances and spending caps still\napply.\n\n## Errors\n\nEvery failure has the same shape, so a client can write one error path:\n\n```json\n{ \"error\": { \"type\": \"invalid_request\", \"message\": \"...\", \"details\": [ ... ] } }\n```\n\nMatch on `type`, which is stable. `message` is for humans and may change\nwithout notice. `details` names the offending fields when the failure is\nattributable to input.\n\n`recipient_opted_out` is its own type rather than a bare `403` because a\ncaller has to be able to tell \"this person unsubscribed, remove them from your\nlist\" apart from \"your key may not do that\". Retrying the first will never\nsucceed.\n\nEvery response carries `X-Correlation-Id`. Quoting it in a support report\nidentifies the exact request in the platform logs.\n\n## Pagination\n\nCollections are cursor-paginated, not offset-paginated: an offset silently\nskips or repeats records when the underlying set changes between pages, which\nit does constantly here.\n\nRead `data`, and if `hasMore` is true, pass `nextCursor` back as\n`cursor`. `nextCursor` is null on the last page, so a client can loop on\nits presence rather than comparing cursors.\n\n## Idempotency\n\n`POST /v1/messages` accepts an `Idempotency-Key` header. A repeat of the\nsame key returns the original message with `200` instead of sending a second\none and returning `202`. The distinction tells a caller retrying after a\ntimeout that its first attempt did land.\n\nKeys are at most 128 characters of letters, digits and `.`, `:`, `_`,\n`-`. An over-long key is rejected rather than truncated, because truncating\nwould silently merge two distinct requests into one message.\n\n## Rate limits\n\nTwo buckets are charged: one for requests generally, and a narrower one for\nsends. A send costs carrier capacity shared with every other tenant, which is\nscarcer than the database query behind a `GET`; one bucket for both would let\na client polling its message list starve its own sending.\n\nEvery response carries `RateLimit-Limit`, `RateLimit-Remaining` and\n`RateLimit-Reset`. A client that reads them never has to be refused at all. A\n`429` also carries `Retry-After`.\n\nA send refused by validation or replayed from an idempotency key is refunded,\nso a client retrying safely is not punished for it.\n\n## Webhooks\n\nEvents are delivered to the account webhook, or to a per-number override, as a\n`POST` with two headers:\n\n```\nPager-Timestamp: 1735689600\nPager-Signature: v1=<hex hmac-sha256>\n```\n\nThe signature covers `${timestamp}.${rawBody}` under the account's own\nsigning secret, which `GET /v1/account` returns. Verify over the raw body\nbefore parsing it, compare in constant time, and reject a timestamp outside a\nfive-minute window — without that check a captured request can be replayed\nforever.\n\nEach account has its own secret. Verification is symmetric, so a shared secret\nwould let any customer mint signatures for any other customer's endpoint.\n\nFailed deliveries are retried on a backoff of 1s, 5s, 30s and 120s — five\nattempts in total. `5xx`, `429`, `408` and network errors are retried;\nevery other `4xx` is final, since a `404` at a mistyped path will still be\na `404`. Redirects are never followed. Every attempt is recorded and readable\nat `GET /v1/webhook_deliveries`.\n\n## Versioning\n\n`/v1` is supported for the life of the product. It has no sunset date, and an\nintegration written against it today keeps working. There are no\n`Deprecation` or `Sunset` headers, because there is nothing for them to\nannounce.\n\nAdditive changes ship into `/v1` without notice: new endpoints, new optional\nrequest fields, new response fields, new values in a field whose published\nschema says it may gain them, new error types for conditions that could not\npreviously arise, and relaxed validation. `message.status` and the `type`\nin a failure body are the fields that carry that warning today. Parse responses\npermissively and treat an unrecognised enumerated value as one you do not\nhandle rather than as an error; a client that rejects unknown fields, or that\nturns a published enumeration into a closed type, will break on a change this\npolicy considers safe.\n\nNothing is ever removed, renamed, retyped or given a new meaning inside\n`/v1`, and no enumeration that does not advertise itself as open gains a\nvalue. An existing condition keeps its status and its error type — including\nagainst being subdivided into a finer one, which would stop the value a client\nmatches on from arriving. A change that cannot be made additively arrives as\n`/v2`, served alongside `/v1` rather than instead of it. Nobody is\nmigrated.\n\nThe major component of `info.version` is the version this document describes\nand matches the prefix its paths are served under. It does not report the\nrunning build — `GET /v1/health` does that."},"servers":[{"url":"https://0.0.0.0:3000"}],"tags":[{"name":"Messages","description":"Sending and reading SMS."},{"name":"Numbers","description":"The numbers an account can send from."},{"name":"Consent","description":"Who may be messaged, and the evidence for it. Carriers require this to be answerable on demand."},{"name":"Webhooks","description":"Delivery of events, and its audit."},{"name":"Account","description":"The account and its API keys."},{"name":"System","description":"Liveness."}],"paths":{"/v1/health":{"get":{"tags":["System"],"operationId":"getHealth","summary":"Liveness probe","description":"Reports only that the process is serving requests. Requires no authentication, so it can be used by a load balancer.","security":[],"responses":{"200":{"description":"The service is up.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","const":"ok"},"service":{"type":"string"},"uptimeSeconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"version":{"type":"string"}},"required":["status","service","uptimeSeconds","version"],"additionalProperties":false}}}}}}},"/v1/account":{"get":{"tags":["Account"],"operationId":"getAccount","summary":"The account this key belongs to","description":"The cheapest way to confirm a key works and to discover which account it acts as, which matters when an operator holds keys for several tenants. Also where a customer collects the secret their webhooks are signed with.","responses":{"200":{"description":"The account.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"status":{"type":"string","enum":["active","suspended"]},"webhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}]},"webhookSigningSecret":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The secret outbound webhooks are signed with. Returned to the owning account and to nobody else."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","name","status","webhookUrl","webhookSigningSecret","createdAt"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/api-keys":{"get":{"tags":["Account"],"operationId":"listApiKeys","summary":"List API keys","description":"Every key ever issued to this account, including revoked ones, so an audit can account for all of them. Secrets are never returned; only a hint of the last few characters.\n\nRead-only. Keys are issued and revoked from the console, which authenticates a person: a key able to mint another key could not be revoked, because whoever took it would issue a replacement first.","responses":{"200":{"description":"The keys.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string","description":"The fixed prefix every Pager key carries."},"hint":{"type":"string","description":"The last few characters, to tell keys apart."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","name","prefix","hint","createdAt","lastUsedAt","revokedAt"],"additionalProperties":false}}},"required":["data"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/messages":{"get":{"tags":["Messages"],"operationId":"listMessages","summary":"List messages","description":"Both directions, newest first. Filters combine, so `direction=outbound&status=failed` is everything that did not get through. An inbound message is stored `delivered`: it has already arrived, so there is no later outcome to wait for.","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["queued","sent","delivered","failed","undelivered"]}},{"name":"direction","in":"query","required":false,"schema":{"type":"string","enum":["inbound","outbound"]}},{"name":"to","in":"query","required":false,"description":"An E.164 phone number, including the leading plus.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},{"name":"from","in":"query","required":false,"description":"An E.164 phone number, including the leading plus.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records to return, from 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"A page of messages.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"from":{"type":"string"},"to":{"type":"string"},"body":{"type":"string"},"status":{"type":"string","enum":["queued","sent","delivered","failed","undelivered"],"description":"May gain values without notice — treat an unrecognised status as one you do not handle rather than as an error. A client that rejects it will break on a change the versioning policy considers additive."},"encoding":{"anyOf":[{"type":"string","enum":["GSM7","UCS2"]},{"type":"null"}],"description":"Null on records that predate stored encoding."},"segments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many segments the carrier billed for."},"priceMicros":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"What this message was priced at, in micro-dollars: 14800 is $0.0148. Denominated below a cent because a segment costs less than one, and a price rounded to cents would be wrong by up to a third. Null on inbound messages and on records that predate metered billing."},"priceVersion":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The rate card this message was priced by. Recorded so a charge can be explained later without assuming current rates applied to it."},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"providerMessageId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The upstream provider's own id for this message. Null until the message is submitted. Quote it when raising a delivery problem with the provider."},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Which configured provider carried the message. Reported so the id above can be taken to the right support desk. Null on records that predate this field."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","direction","from","to","body","status","encoding","segments","priceMicros","priceVersion","errorCode","errorMessage","providerMessageId","provider","createdAt","updatedAt"],"additionalProperties":false}},"hasMore":{"type":"boolean"},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `cursor` for the next page. Null on the last page."}},"required":["data","hasMore","nextCursor"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"tags":["Messages"],"operationId":"sendMessage","summary":"Send an SMS","description":"Returns `202`, not `200`. The message is recorded and queued; the carrier has not seen it yet. Delivery is reported later through `status` and through webhooks.\n\nThe response carries the computed segment count, encoding and price, because carriers bill per segment and a single emoji can turn a one-segment message into three. The price is in micro-dollars, since a segment costs less than a cent.\n\nSending is prepaid. A request that would overdraw the account fails with `insufficient_balance` and `402`, records nothing, and succeeds unchanged once credit is added.\n\nAn account may also cap its own sending per day or per calendar month, in the console. A request past a cap fails with `spend_cap_exceeded` and `402`, and records nothing. It is not a balance problem: the money is there, and topping up will not help. The message names which cap stopped it; the ways through are to raise it or to wait for the period to roll over.\n\nSending to a number that has opted out fails with `recipient_opted_out`; that is final, and the number must be removed from the list rather than retried.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Repeat a request safely. A replay returns the original message with `200` rather than sending again. At most 128 characters of letters, digits and `.`, `:`, `_`, `-`.","schema":{"type":"string","maxLength":128,"pattern":"^[\\w.:-]+$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"An SMS-capable E.164 number assigned to your account. For an approved international route, the carrier uses its configured branded sender while this remains the logical sender in message records."},"to":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"Destination in E.164 format. Must have an approved price; international sending also requires a configured route for your sending number."},"body":{"type":"string","minLength":1,"description":"The text to send."}},"required":["from","to","body"]}}}},"responses":{"200":{"description":"A replay of an earlier request with the same `Idempotency-Key`. Nothing was sent this time.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"from":{"type":"string"},"to":{"type":"string"},"body":{"type":"string"},"status":{"type":"string","enum":["queued","sent","delivered","failed","undelivered"],"description":"May gain values without notice — treat an unrecognised status as one you do not handle rather than as an error. A client that rejects it will break on a change the versioning policy considers additive."},"encoding":{"anyOf":[{"type":"string","enum":["GSM7","UCS2"]},{"type":"null"}],"description":"Null on records that predate stored encoding."},"segments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many segments the carrier billed for."},"priceMicros":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"What this message was priced at, in micro-dollars: 14800 is $0.0148. Denominated below a cent because a segment costs less than one, and a price rounded to cents would be wrong by up to a third. Null on inbound messages and on records that predate metered billing."},"priceVersion":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The rate card this message was priced by. Recorded so a charge can be explained later without assuming current rates applied to it."},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"providerMessageId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The upstream provider's own id for this message. Null until the message is submitted. Quote it when raising a delivery problem with the provider."},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Which configured provider carried the message. Reported so the id above can be taken to the right support desk. Null on records that predate this field."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","direction","from","to","body","status","encoding","segments","priceMicros","priceVersion","errorCode","errorMessage","providerMessageId","provider","createdAt","updatedAt"],"additionalProperties":false}}}},"202":{"description":"Accepted and queued.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"from":{"type":"string"},"to":{"type":"string"},"body":{"type":"string"},"status":{"type":"string","enum":["queued","sent","delivered","failed","undelivered"],"description":"May gain values without notice — treat an unrecognised status as one you do not handle rather than as an error. A client that rejects it will break on a change the versioning policy considers additive."},"encoding":{"anyOf":[{"type":"string","enum":["GSM7","UCS2"]},{"type":"null"}],"description":"Null on records that predate stored encoding."},"segments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many segments the carrier billed for."},"priceMicros":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"What this message was priced at, in micro-dollars: 14800 is $0.0148. Denominated below a cent because a segment costs less than one, and a price rounded to cents would be wrong by up to a third. Null on inbound messages and on records that predate metered billing."},"priceVersion":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The rate card this message was priced by. Recorded so a charge can be explained later without assuming current rates applied to it."},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"providerMessageId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The upstream provider's own id for this message. Null until the message is submitted. Quote it when raising a delivery problem with the provider."},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Which configured provider carried the message. Reported so the id above can be taken to the right support desk. Null on records that predate this field."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","direction","from","to","body","status","encoding","segments","priceMicros","priceVersion","errorCode","errorMessage","providerMessageId","provider","createdAt","updatedAt"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/InsufficientBalance"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/messages/{id}":{"get":{"tags":["Messages"],"operationId":"getMessage","summary":"Fetch a message","parameters":[{"name":"id","in":"path","required":true,"description":"The message id.","schema":{"type":"string"}}],"responses":{"200":{"description":"The message.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"from":{"type":"string"},"to":{"type":"string"},"body":{"type":"string"},"status":{"type":"string","enum":["queued","sent","delivered","failed","undelivered"],"description":"May gain values without notice — treat an unrecognised status as one you do not handle rather than as an error. A client that rejects it will break on a change the versioning policy considers additive."},"encoding":{"anyOf":[{"type":"string","enum":["GSM7","UCS2"]},{"type":"null"}],"description":"Null on records that predate stored encoding."},"segments":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991,"description":"How many segments the carrier billed for."},"priceMicros":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"What this message was priced at, in micro-dollars: 14800 is $0.0148. Denominated below a cent because a segment costs less than one, and a price rounded to cents would be wrong by up to a third. Null on inbound messages and on records that predate metered billing."},"priceVersion":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The rate card this message was priced by. Recorded so a charge can be explained later without assuming current rates applied to it."},"errorCode":{"anyOf":[{"type":"string"},{"type":"null"}]},"errorMessage":{"anyOf":[{"type":"string"},{"type":"null"}]},"providerMessageId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The upstream provider's own id for this message. Null until the message is submitted. Quote it when raising a delivery problem with the provider."},"provider":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Which configured provider carried the message. Reported so the id above can be taken to the right support desk. Null on records that predate this field."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","direction","from","to","body","status","encoding","segments","priceMicros","priceVersion","errorCode","errorMessage","providerMessageId","provider","createdAt","updatedAt"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/numbers":{"get":{"tags":["Numbers"],"operationId":"listNumbers","summary":"List numbers","description":"The inventory this account may send from. Which carrier a number rides on is deliberately not reported: it is a routing decision the platform makes and changes.","parameters":[{"name":"capability","in":"query","required":false,"schema":{"type":"string","enum":["voice","sms"]}},{"name":"country","in":"query","required":false,"description":"An ISO 3166-1 alpha-2 country code.","schema":{"type":"string","minLength":2,"maxLength":2}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records to return, from 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"A page of numbers.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"phoneNumber":{"type":"string"},"capabilities":{"type":"array","items":{"type":"string","enum":["voice","sms"]}},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"inboundEnabled":{"type":"boolean"},"inboundWebhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Overrides the account webhook for this number when set."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","phoneNumber","capabilities","country","inboundEnabled","inboundWebhookUrl","createdAt","updatedAt"],"additionalProperties":false}},"hasMore":{"type":"boolean"},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `cursor` for the next page. Null on the last page."}},"required":["data","hasMore","nextCursor"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/numbers/{phoneNumber}":{"get":{"tags":["Numbers"],"operationId":"getNumber","summary":"Fetch a number","parameters":[{"name":"phoneNumber","in":"path","required":true,"description":"The number in E.164, url-encoded or not; `+12125551234` and `%2B12125551234` both work.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}}],"responses":{"200":{"description":"The number.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"phoneNumber":{"type":"string"},"capabilities":{"type":"array","items":{"type":"string","enum":["voice","sms"]}},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"inboundEnabled":{"type":"boolean"},"inboundWebhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Overrides the account webhook for this number when set."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","phoneNumber","capabilities","country","inboundEnabled","inboundWebhookUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"tags":["Numbers"],"operationId":"updateNumber","summary":"Update a number","description":"Supply at least one of `inboundEnabled` or `inboundWebhookUrl`; an empty patch is rejected. Setting `inboundWebhookUrl` to `null` clears the override and returns the number to the account default, which is the only way a PATCH can express \"remove this\".","parameters":[{"name":"phoneNumber","in":"path","required":true,"description":"The number in E.164.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"inboundEnabled":{"type":"boolean"},"inboundWebhookUrl":{"anyOf":[{"type":"string","maxLength":2000,"pattern":"^https:\\/\\/"},{"type":"null"}]}}}}}},"responses":{"200":{"description":"The updated number.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"phoneNumber":{"type":"string"},"capabilities":{"type":"array","items":{"type":"string","enum":["voice","sms"]}},"country":{"anyOf":[{"type":"string"},{"type":"null"}]},"inboundEnabled":{"type":"boolean"},"inboundWebhookUrl":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Overrides the account webhook for this number when set."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","phoneNumber","capabilities","country","inboundEnabled","inboundWebhookUrl","createdAt","updatedAt"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/consent":{"get":{"tags":["Consent"],"operationId":"listConsent","summary":"List consent records","description":"The current state for every number this account knows.","parameters":[{"name":"state","in":"query","required":false,"schema":{"type":"string","enum":["opted_in","opted_out"]}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records to return, from 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"A page of consent records.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"phoneNumber":{"type":"string"},"state":{"type":"string","enum":["opted_in","opted_out"]},"source":{"type":"string","enum":["keyword","web","api","operator"]},"keyword":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["phoneNumber","state","source","keyword","createdAt","updatedAt"],"additionalProperties":false}},"hasMore":{"type":"boolean"},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `cursor` for the next page. Null on the last page."}},"required":["data","hasMore","nextCursor"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"tags":["Consent"],"operationId":"recordConsent","summary":"Record consent","description":"Returns `200`, not `201`: there is one record per number and this either created or replaced it, so a caller cannot read `201` as \"was not already known\".\n\nSupply `ipAddress` and `consentText` for an opt-in. An opt-out never needs justifying, but an opt-in without evidence is an assertion with nothing behind it — which is what a carrier will ask you to produce.\n\nConsent recorded here never overrides a STOP received by keyword; a handset always wins.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"An E.164 phone number, including the leading plus."},"state":{"type":"string","enum":["opted_in","opted_out"]},"ipAddress":{"type":"string","maxLength":64},"consentText":{"type":"string","maxLength":2000}},"required":["phoneNumber","state"]}}}},"responses":{"200":{"description":"The consent record.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string"},"state":{"type":"string","enum":["opted_in","opted_out"]},"source":{"type":"string","enum":["keyword","web","api","operator"]},"keyword":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["phoneNumber","state","source","keyword","createdAt","updatedAt"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/consent/{phoneNumber}":{"get":{"tags":["Consent"],"operationId":"getConsentHistory","summary":"Consent history for a number","description":"Every change, newest first, with what caused it. This is the answer to a carrier asking why a number was messaged.","parameters":[{"name":"phoneNumber","in":"path","required":true,"description":"The number in E.164.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records to return, from 1 to 200.","schema":{"type":"integer","minimum":1,"maximum":200}}],"responses":{"200":{"description":"The number's current consent state and a page of the events that produced it.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"phoneNumber":{"type":"string"},"state":{"type":"string","enum":["opted_in","opted_out"]},"source":{"type":"string","enum":["keyword","web","api","operator"]},"keyword":{"anyOf":[{"type":"string"},{"type":"null"}]},"ipAddress":{"anyOf":[{"type":"string"},{"type":"null"}]},"consentText":{"anyOf":[{"type":"string"},{"type":"null"}]},"messageId":{"anyOf":[{"type":"string"},{"type":"null"}]},"occurredAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","phoneNumber","state","source","keyword","ipAddress","consentText","messageId","occurredAt"],"additionalProperties":false}},"hasMore":{"type":"boolean"},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `cursor` for the next page. Null on the last page."},"phoneNumber":{"type":"string"},"state":{"anyOf":[{"type":"string","enum":["opted_in","opted_out"]},{"type":"null"}]},"record":{"anyOf":[{"type":"object","properties":{"phoneNumber":{"type":"string"},"state":{"type":"string","enum":["opted_in","opted_out"]},"source":{"type":"string","enum":["keyword","web","api","operator"]},"keyword":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["phoneNumber","state","source","keyword","createdAt","updatedAt"],"additionalProperties":false},{"type":"null"}]}},"required":["data","hasMore","nextCursor","phoneNumber","state","record"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/verified_numbers":{"get":{"tags":["Verified numbers"],"operationId":"listVerifiedNumbers","summary":"List verified destinations","description":"The numbers this account has proved it controls. Live accounts see whatever they verified while sandboxed; the records are kept, they are simply no longer consulted.","responses":{"200":{"description":"Every destination, verified or pending.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"phoneNumber":{"type":"string"},"status":{"type":"string","enum":["pending","verified"]},"verifiedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["phoneNumber","status","verifiedAt","createdAt"],"additionalProperties":false}}},"required":["data"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"tags":["Verified numbers"],"operationId":"startNumberVerification","summary":"Send a verification code","description":"Texts a six-digit code to the number, then confirm it with `POST /v1/verified_numbers/{phoneNumber}`.\n\nReturns `202` when a code is on its way and `200` when the number was already verified — in which case no message is sent and nothing is charged.\n\nRate limited per destination *and* per account, because every call sends a real SMS. A number that has opted out is never texted a code: proving you control a handset is not an exception to STOP. That case returns `403`, and the handset must text `START` back to the verification number named in the error before any code can reach it — nothing you can do from the API will clear it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$","description":"An E.164 phone number, including the leading plus."}},"required":["phoneNumber"]}}}},"responses":{"200":{"description":"The number was already verified.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string"},"status":{"type":"string","enum":["pending","verified"]}},"required":["phoneNumber","status"],"additionalProperties":false}}}},"202":{"description":"A code is on its way.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string"},"status":{"type":"string","enum":["pending","verified"]}},"required":["phoneNumber","status"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/v1/verified_numbers/{phoneNumber}":{"post":{"tags":["Verified numbers"],"operationId":"confirmNumberVerification","summary":"Confirm a verification code","description":"Five wrong guesses spend the code and a new one must be requested. Every failure — wrong, expired, never issued, budget spent — returns the same error on purpose, so that the response cannot be used to tell how much of the space is left.","parameters":[{"name":"phoneNumber","in":"path","required":true,"description":"The number in E.164.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string","pattern":"^[0-9]{6}$"}},"required":["code"]}}}},"responses":{"200":{"description":"The number is verified.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"phoneNumber":{"type":"string"},"status":{"type":"string","enum":["pending","verified"]}},"required":["phoneNumber","status"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"tags":["Verified numbers"],"operationId":"deleteVerifiedNumber","summary":"Remove a destination","description":"Removes the destination whether it was verified or merely pending. A sandbox key can no longer send to it.","parameters":[{"name":"phoneNumber","in":"path","required":true,"description":"The number in E.164.","schema":{"type":"string","pattern":"^\\+[1-9]\\d{1,14}$"}}],"responses":{"204":{"description":"Removed."},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/v1/webhook_deliveries":{"get":{"tags":["Webhooks"],"operationId":"listWebhookDeliveries","summary":"List webhook deliveries","description":"What was sent to your endpoint, and what it answered. Each record carries the full attempt log, because the question this answers is \"why did my endpoint not get this\", and the answer is always in the attempts.","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","succeeded","failed"]}},{"name":"eventType","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"cursor","in":"query","required":false,"description":"The `nextCursor` from the previous page.","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"How many records to return, from 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100}}],"responses":{"200":{"description":"A page of deliveries.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"eventId":{"type":"string"},"eventType":{"type":"string"},"url":{"type":"string"},"status":{"type":"string","enum":["pending","succeeded","failed"]},"attempts":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"responseStatus":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"deliveredAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"attemptLog":{"type":"array","items":{"type":"object","properties":{"attempt":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"responseStatus":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"error":{"anyOf":[{"type":"string"},{"type":"null"}]},"durationMs":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["attempt","at","responseStatus","error","durationMs"],"additionalProperties":false}}},"required":["id","eventId","eventType","url","status","attempts","responseStatus","error","deliveredAt","createdAt","updatedAt","attemptLog"],"additionalProperties":false}},"hasMore":{"type":"boolean"},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Pass as `cursor` for the next page. Null on the last page."}},"required":["data","hasMore","nextCursor"],"additionalProperties":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/InvalidRequest"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key, issued from the console or the operator CLI."}},"responses":{"Unauthorized":{"description":"The key is missing, malformed, revoked, or its account is suspended.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"Forbidden":{"description":"Permitted to authenticate but not to do this — including `recipient_opted_out`, which is final.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"NotFound":{"description":"No such resource, or it belongs to another account. The two are deliberately indistinguishable.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"InvalidRequest":{"description":"The request failed validation. `details` names the fields.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"InsufficientBalance":{"description":"The account has not got enough credit for this message. The message says what the balance is and what the message costs. Nothing was recorded and nothing was sent; add credit and repeat the request unchanged.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"RateLimited":{"description":"Too many requests. Wait for `Retry-After` seconds.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}},"RateLimit-Limit":{"description":"Requests permitted in the current window.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests still available.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the bucket refills.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"InternalError":{"description":"Something failed on our side. The correlation id identifies it in our logs.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"ServiceUnavailable":{"description":"The feature is not configured on this deployment. Nothing about the request was wrong; retrying it unchanged will not help until an operator fixes the deployment.","headers":{"X-Correlation-Id":{"description":"Identifies this request in the platform logs. Quote it in a support report and the exact request can be found.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"type":{"type":"string","enum":["unauthorized","forbidden","not_found","invalid_request","conflict","recipient_opted_out","destination_not_verified","destination_not_supported","insufficient_balance","spend_cap_exceeded","rate_limited","service_unavailable","internal_error"],"description":"May gain values without notice, as conditions that could not previously arise get types of their own. A condition that already has a type keeps it, so a value you match on will not stop arriving. Fall back to the HTTP status for a type you do not recognise."},"message":{"type":"string","description":"For humans. May change without notice; match on `type`."},"details":{"description":"Present when the failure is attributable to input fields.","type":"array","items":{"type":"object","properties":{"field":{"type":"string"},"message":{"type":"string"}},"required":["field","message"],"additionalProperties":false}}},"required":["type","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"security":[{"bearerAuth":[]}]}