Idempotency-Key is mandatory — retrying a timeout must never
double-text anyone. Only a 201 is replayed; a validation failure or a
provider rejection releases the key so a corrected retry can reuse
it. The same key with a different body is 409, and a second request
while the first is in flight is also 409.
Every attempt that reaches the provider is logged, sent or failed — the
row is the audit trail. A provider rejection is therefore a 502 that
still carries the logged row’s messageId.
A successful send also enqueues an interaction.completed webhook with
channel: "sms", on the same stream as voice.
Required. A retry with the same key and body replays the stored 2xx response; the same key with a different body is 409. A failed attempt releases the key.
The payload Vodex POSTs to your endpoint — not something this API
serves. Documented here because it is the contract configured through
PUT /v1/webhook-config.
interaction.completed, not call.completed: one stream for every
channel, so a consumer writes one handler and switches on channel
rather than integrating a new webhook when SMS or WhatsApp ships.
It is deliberately complete — a consumer that receives this needs no
follow-up GET. analysis is an open envelope: summary and sentiment
land there as additive keys, so a handler written today keeps parsing
tomorrow's payloads.
Headers
Header
Meaning
x-vodex-signature
t=<unix>,v1=<hex> where v1 = HMAC-SHA256(secret, "<t>.<raw body>")
x-vodex-event
The event type
x-vodex-delivery
Delivery id — the same event retried keeps its id, so use that for idempotency
The timestamp is inside the signed string, not merely alongside it:
signing the body alone leaves a captured delivery replayable forever,
because nothing in what was signed says when it was sent. Reject
anything more than 300 seconds off in either direction. During a
rotation both secrets sign, as repeated v1= values, so consumers can
move without a coordinated deploy.
Retries
8 attempts at 10s, 30s, 2m, 10m, 30m, 2h, 6h, each with full jitter
(a random point in [0, delay], so a consumer coming back from an
outage is not hit by every queued delivery at the same instant). 408,
429, 5xx and transport failures retry; every other 4xx does not —
repeating a request the consumer called wrong just burns the budget a
real outage needs. A delivery that exhausts its attempts is the dead
letter — status: failed with no nextAttemptAt — and stays visible at
GET /v1/webhook-deliveries.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Vodex API","description":"The public Vodex /v1 REST API — assistants, telephony, calls, batches, SMS and webhooks.","colors":{"primary":"#FF4D00","light":"#FF4D00","dark":"#FF4D00"},"logo":{"light":"https://mintcdn.com/vodex/78No6_lqTF_DicwD/logo/vodex-full.svg?fit=max\u0026auto=format\u0026n=78No6_lqTF_DicwD\u0026q=85\u0026s=abc36083e47f9332141ac1141d1cbe4a","dark":"https://mintcdn.com/vodex/78No6_lqTF_DicwD/logo/vodex-full.svg?fit=max\u0026auto=format\u0026n=78No6_lqTF_DicwD\u0026q=85\u0026s=abc36083e47f9332141ac1141d1cbe4a"},"favicon":"https://mintcdn.com/vodex/78No6_lqTF_DicwD/favicon.png?fit=max\u0026auto=format\u0026n=78No6_lqTF_DicwD\u0026q=85\u0026s=a3598c2265371fff3cd08244e8e6cf66","appearance":{"default":"system"},"navbar":{"links":[{"href":"mailto:support@vodex.ai","label":"Support"},{"href":"https://vodex.ai","label":"vodex.ai"}],"primary":{"type":"button","label":"Console","href":"https://console.vodex.ai"}},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"vodex","hasAudioNarration":false,"actualSubdomain":"vodex","customDomains":["apidocs.vodex.ai"],"gitSource":{"type":"github","owner":"lilchirpio","repo":"vodex","deployBranch":"main","contentDirectory":"docs-site","isPrivate":true,"mountPath":"","label":""},"chroma":{"latestBuiltDeploymentHistoryId":"6ae4c8c238fcbf2314c7045c","collectionId":"d3294b7d-8c93-44c2-95a0-17739dc4bfb2","liveDeploymentHistoryId":"6ae4c8c238fcbf2314c7045c","schemaVersion":"v3"},"entitlements":{},"buildId":"6ae4c8c238fcbf2314c7045c","clientVersion":"0.0.4044","searchFilterCounts":[{"language":"default","tag":"API Reference","count":155},{"language":"default","tag":"Contacts","count":27},{"language":"default","tag":"Batches","count":16},{"language":"default","tag":"Campaigns","count":14},{"language":"default","tag":"Assistants","count":12},{"language":"default","tag":"SMS","count":12},{"language":"default","tag":"Audiences","count":8},{"language":"default","tag":"Do Not Contact","count":8},{"language":"default","tag":"Integrations","count":8},{"language":"default","tag":"Payments","count":8}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"api-reference/sms/send-an-sms","slug":"/api-reference/sms/send-an-sms","pageMetadata":{"title":"Send an SMS","description":"`Idempotency-Key` is **mandatory** — retrying a timeout must never\ndouble-text anyone. Only a `201` is replayed; a validation failure or a\nprovider rejection **releases** the key so a corrected retry can reuse\nit. The same key with a different body is `409`, and a second request\nwhile the first is in flight is also `409`.\n\nEvery attempt that reaches the provider is logged, sent or failed — the\nrow *is* the audit trail. A provider rejection is therefore a `502` that\nstill carries the logged row's `messageId`.\n\nA successful send also enqueues an `interaction.completed` webhook with\n`channel: \"sms\"`, on the same stream as voice.\n","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sms","href":"/api-reference/sms/send-an-sms","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n em: \"em\",\n p: \"p\",\n strong: \"strong\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"Idempotency-Key\"\n }), \" is \", _jsx(_components.strong, {\n children: \"mandatory\"\n }), \" — retrying a timeout must never\\ndouble-text anyone. Only a \", _jsx(_components.code, {\n children: \"201\"\n }), \" is replayed; a validation failure or a\\nprovider rejection \", _jsx(_components.strong, {\n children: \"releases\"\n }), \" the key so a corrected retry can reuse\\nit. The same key with a different body is \", _jsx(_components.code, {\n children: \"409\"\n }), \", and a second request\\nwhile the first is in flight is also \", _jsx(_components.code, {\n children: \"409\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Every attempt that reaches the provider is logged, sent or failed — the\\nrow \", _jsx(_components.em, {\n children: \"is\"\n }), \" the audit trail. A provider rejection is therefore a \", _jsx(_components.code, {\n children: \"502\"\n }), \" that\\nstill carries the logged row’s \", _jsx(_components.code, {\n children: \"messageId\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A successful send also enqueues an \", _jsx(_components.code, {\n children: \"interaction.completed\"\n }), \" webhook with\\n\", _jsx(_components.code, {\n children: \"channel: \\\"sms\\\"\"\n }), \", on the same stream as voice.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Send an SMS","description":"`Idempotency-Key` is **mandatory** — retrying a timeout must never\ndouble-text anyone. Only a `201` is replayed; a validation failure or a\nprovider rejection **releases** the key so a corrected retry can reuse\nit. The same key with a different body is `409`, and a second request\nwhile the first is in flight is also `409`.\n\nEvery attempt that reaches the provider is logged, sent or failed — the\nrow *is* the audit trail. A provider rejection is therefore a `502` that\nstill carries the logged row's `messageId`.\n\nA successful send also enqueues an `interaction.completed` webhook with\n`channel: \"sms\"`, on the same stream as voice.\n","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sms","href":"/api-reference/sms/send-an-sms","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"operationId":"sendSms","tags":["SMS"],"summary":"Send an SMS","description":"`Idempotency-Key` is **mandatory** — retrying a timeout must never\ndouble-text anyone. Only a `201` is replayed; a validation failure or a\nprovider rejection **releases** the key so a corrected retry can reuse\nit. The same key with a different body is `409`, and a second request\nwhile the first is in flight is also `409`.\n\nEvery attempt that reaches the provider is logged, sent or failed — the\nrow *is* the audit trail. A provider rejection is therefore a `502` that\nstill carries the logged row's `messageId`.\n\nA successful send also enqueues an `interaction.completed` webhook with\n`channel: \"sms\"`, on the same stream as voice.\n","parameters":["853c274f-cfb2-4b95-8044-c1d25ac36b99"],"requestBody":"1edddda3-bb80-485c-b33a-be0481c78d36","responses":{"201":"84aaf431-2234-49c3-8f08-c1e67f21dfd6","400":"548a4cc0-cfcb-4319-aaa7-c5366cbf856f","404":"db950489-261c-405d-bd1c-8998553f931e","409":"b24b0953-5a17-42c4-a7a5-6fba595cd3ae","422":"937a1b6b-1d0f-4d34-aa03-1a80a379cb61","502":"ff2a2a9f-a1c3-4eae-94b4-3836c338224f"},"callbacks":{"interactionCompleted":"491357e2-191b-46fa-9067-6ca42d745652"},"method":"post","type":"path","servers":["454f84ff-3690-4156-8c58-c64805db6548"],"security":["986b34dc-9d64-43d6-addf-8d27adc5ae4e"],"path":"/sms","baseUrlOptions":["https://apiv2.vodex.ai/v1"],"title":"Send an SMS","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"853c274f-cfb2-4b95-8044-c1d25ac36b99":{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":255,"isRequired":true,"description":"Required. A retry with the same key and body replays the stored 2xx response; the same key with a different body is `409`. A failed attempt releases the key.","uniqueKey":"","typeLabel":"string"},"description":"Required. A retry with the same key and body replays the stored 2xx response; the same key with a different body is `409`. A failed attempt releases the key."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to"],"properties":{"to":{"type":"string","description":"E.164.","isRequired":true,"uniqueKey":"to","typeLabel":"string"},"message":{"type":"string","description":"Free text; wins over the configuration's body.","uniqueKey":"message","typeLabel":"string"},"smsConfigurationId":{"type":"string","format":"uuid","description":"Defaults to the tenant's default configuration.","uniqueKey":"smsConfigurationId","typeLabel":"string\u003cuuid>"},"templateId":{"type":"string","description":"Provider template; the provider renders it.","uniqueKey":"templateId","typeLabel":"string"},"from":{"type":"string","description":"E.164 override.","uniqueKey":"from","typeLabel":"string"},"variables":{"type":"object","uniqueKey":"variables","typeLabel":"object"},"contactRef":{"type":"string","description":"Opaque consumer reference, echoed on the webhook.","uniqueKey":"contactRef","typeLabel":"string"},"callId":{"type":"string","description":"Links this message to a call.","uniqueKey":"callId","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"to":"\u003cstring>","message":"\u003cstring>","smsConfigurationId":"3c90c3cc-0d44-4b50-8888-8dd25736052a","templateId":"\u003cstring>","from":"\u003cstring>","variables":{},"contactRef":"\u003cstring>","callId":"\u003cstring>"}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"84aaf431-2234-49c3-8f08-c1e67f21dfd6":{"description":"Sent.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","uniqueKey":"id","typeLabel":"string\u003cuuid>"},"configurationId":{"oneOf":[{"type":"string","format":"uuid","uniqueKey":"configurationId.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","uniqueKey":"configurationId.oneOf.1","typeLabel":"null"}],"uniqueKey":"configurationId","typeLabel":"string\u003cuuid> | null"},"direction":{"type":"string","enum":["outbound","inbound"],"uniqueKey":"direction","typeLabel":"enum\u003cstring>"},"toNumber":{"type":"string","uniqueKey":"toNumber","typeLabel":"string"},"fromNumber":{"oneOf":[{"type":"string","uniqueKey":"fromNumber.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"fromNumber.oneOf.1","typeLabel":"null"}],"uniqueKey":"fromNumber","typeLabel":"string | null"},"body":{"type":"string","uniqueKey":"body","typeLabel":"string"},"status":{"type":"string","enum":["queued","sent","delivered","failed"],"uniqueKey":"status","typeLabel":"enum\u003cstring>"},"provider":{"type":"string","uniqueKey":"provider","typeLabel":"string"},"providerMessageId":{"oneOf":[{"type":"string","uniqueKey":"providerMessageId.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"providerMessageId.oneOf.1","typeLabel":"null"}],"uniqueKey":"providerMessageId","typeLabel":"string | null"},"error":{"oneOf":[{"type":"string","uniqueKey":"error.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"error.oneOf.1","typeLabel":"null"}],"uniqueKey":"error","typeLabel":"string | null"},"contactRef":{"oneOf":[{"type":"string","uniqueKey":"contactRef.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"contactRef.oneOf.1","typeLabel":"null"}],"uniqueKey":"contactRef","typeLabel":"string | null"},"callId":{"oneOf":[{"type":"string","uniqueKey":"callId.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"callId.oneOf.1","typeLabel":"null"}],"uniqueKey":"callId","typeLabel":"string | null"},"createdAt":{"type":"string","format":"date-time","uniqueKey":"createdAt","typeLabel":"string\u003cdate-time>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"id":"3c90c3cc-0d44-4b50-8888-8dd25736052a","configurationId":"3c90c3cc-0d44-4b50-8888-8dd25736052a","direction":"outbound","toNumber":"\u003cstring>","fromNumber":"\u003cstring>","body":"\u003cstring>","status":"queued","provider":"\u003cstring>","providerMessageId":"\u003cstring>","error":"\u003cstring>","contactRef":"\u003cstring>","callId":"\u003cstring>","createdAt":"2023-11-07T05:31:56Z"}}},"exampleType":"generated"}},"exampleType":"generated"},"548a4cc0-cfcb-4319-aaa7-c5366cbf856f":{"description":"Missing or malformed `Idempotency-Key`, or a bad `to`/`from`.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"not found","uniqueKey":"error","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"not found"}}},"exampleType":"generated"}},"exampleType":"generated"},"db950489-261c-405d-bd1c-8998553f931e":{"description":"Unknown SMS configuration.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"not found","uniqueKey":"error","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"not found"}}},"exampleType":"generated"}},"exampleType":"generated"},"b24b0953-5a17-42c4-a7a5-6fba595cd3ae":{"description":"Idempotency-Key conflict, or a request with that key is in flight.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"not found","uniqueKey":"error","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"not found"}}},"exampleType":"generated"}},"exampleType":"generated"},"937a1b6b-1d0f-4d34-aa03-1a80a379cb61":{"description":"Nothing to send, or the configuration cannot send this message.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"not found","uniqueKey":"error","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"not found"}}},"exampleType":"generated"}},"exampleType":"generated"},"ff2a2a9f-a1c3-4eae-94b4-3836c338224f":{"description":"The provider rejected the message — logged, with its row id.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","uniqueKey":"error","typeLabel":"string"},"messageId":{"type":"string","format":"uuid","uniqueKey":"messageId","typeLabel":"string\u003cuuid>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":"\u003cstring>","messageId":"3c90c3cc-0d44-4b50-8888-8dd25736052a"}}},"exampleType":"generated"}},"exampleType":"generated"}},"callbacks":[{"callbackName":"interactionCompleted","expression":"{$request.body#/webhookUrl}","method":"post","resolved":{"operation":{"summary":"interaction.completed (channel = sms)","description":"The same envelope voice calls use — one stream for every channel, so a consumer switches on `channel` rather than integrating a second webhook.","requestBody":"c128e51b-963a-4f50-98fb-58aeae49dfc1","responses":{"408":"5f965f0d-4a59-4e90-9ed4-26cd65fc30a4","429":"73ee9e31-1e07-4ae5-a80f-78a9717ed844","2XX":"ad86f00b-9108-487d-839e-288afad21a6a","5XX":"fb0c11fa-b526-48ef-9d41-b1877267d3e4","4XX":"762b5d3b-3c83-411c-9024-e3bbe3c8836c"},"method":"post","type":"path"},"dependencies":{"parameters":{},"requestBody":{"content":{"application/json":{"schema":{"type":"object","description":"**The payload Vodex POSTs to your endpoint** — not something this API\nserves. Documented here because it is the contract configured through\n`PUT /v1/webhook-config`.\n\n`interaction.completed`, not `call.completed`: one stream for every\nchannel, so a consumer writes one handler and switches on `channel`\nrather than integrating a new webhook when SMS or WhatsApp ships.\n\nIt is deliberately **complete** — a consumer that receives this needs no\nfollow-up GET. `analysis` is an open envelope: summary and sentiment\nland there as additive keys, so a handler written today keeps parsing\ntomorrow's payloads.\n\n### Headers\n\n| Header | Meaning |\n|---|---|\n| `x-vodex-signature` | `t=\u003cunix>,v1=\u003chex>` where `v1 = HMAC-SHA256(secret, \"\u003ct>.\u003craw body>\")` |\n| `x-vodex-event` | The event type |\n| `x-vodex-delivery` | Delivery id — the same event retried keeps its `id`, so use that for idempotency |\n\nThe timestamp is **inside** the signed string, not merely alongside it:\nsigning the body alone leaves a captured delivery replayable forever,\nbecause nothing in what was signed says when it was sent. Reject\nanything more than **300 seconds** off in either direction. During a\nrotation both secrets sign, as repeated `v1=` values, so consumers can\nmove without a coordinated deploy.\n\n### Retries\n\n8 attempts at 10s, 30s, 2m, 10m, 30m, 2h, 6h, each with **full jitter**\n(a random point in `[0, delay]`, so a consumer coming back from an\noutage is not hit by every queued delivery at the same instant). 408,\n429, 5xx and transport failures retry; every other 4xx does not —\nrepeating a request the consumer called wrong just burns the budget a\nreal outage needs. A delivery that exhausts its attempts is the dead\nletter — `status: failed` with no `nextAttemptAt` — and stays visible at\n`GET /v1/webhook-deliveries`.\n","properties":{"type":{"type":"string","enum":["interaction.completed"],"uniqueKey":"type","typeLabel":"enum\u003cstring>"},"id":{"type":"string","description":"Idempotency key — stable across retries.","uniqueKey":"id","typeLabel":"string"},"tenantId":{"type":"string","format":"uuid","uniqueKey":"tenantId","typeLabel":"string\u003cuuid>"},"channel":{"type":"string","enum":["voice-ai","sms"],"uniqueKey":"channel","typeLabel":"enum\u003cstring>"},"contactRef":{"oneOf":[{"type":"string","description":"Echoed from the dial request, never interpreted.","uniqueKey":"contactRef.oneOf.0","typeLabel":"string"},{"type":"null","description":"Echoed from the dial request, never interpreted.","uniqueKey":"contactRef.oneOf.1","typeLabel":"null"}],"uniqueKey":"contactRef","typeLabel":"string | null"},"rawAddress":{"oneOf":[{"type":"string","description":"The counterparty address, for when no `contactRef` was passed.","uniqueKey":"rawAddress.oneOf.0","typeLabel":"string"},{"type":"null","description":"The counterparty address, for when no `contactRef` was passed.","uniqueKey":"rawAddress.oneOf.1","typeLabel":"null"}],"uniqueKey":"rawAddress","typeLabel":"string | null"},"direction":{"type":"string","uniqueKey":"direction","typeLabel":"string"},"from":{"oneOf":[{"type":"string","uniqueKey":"from.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"from.oneOf.1","typeLabel":"null"}],"uniqueKey":"from","typeLabel":"string | null"},"to":{"oneOf":[{"type":"string","uniqueKey":"to.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"to.oneOf.1","typeLabel":"null"}],"uniqueKey":"to","typeLabel":"string | null"},"assistantId":{"oneOf":[{"type":"string","uniqueKey":"assistantId.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"assistantId.oneOf.1","typeLabel":"null"}],"uniqueKey":"assistantId","typeLabel":"string | null"},"engine":{"oneOf":[{"type":"string","uniqueKey":"engine.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"engine.oneOf.1","typeLabel":"null"}],"uniqueKey":"engine","typeLabel":"string | null"},"startedAt":{"oneOf":[{"type":"string","format":"date-time","uniqueKey":"startedAt.oneOf.0","typeLabel":"string\u003cdate-time>"},{"type":"null","format":"date-time","uniqueKey":"startedAt.oneOf.1","typeLabel":"null"}],"uniqueKey":"startedAt","typeLabel":"string\u003cdate-time> | null"},"endedAt":{"oneOf":[{"type":"string","format":"date-time","uniqueKey":"endedAt.oneOf.0","typeLabel":"string\u003cdate-time>"},{"type":"null","format":"date-time","uniqueKey":"endedAt.oneOf.1","typeLabel":"null"}],"uniqueKey":"endedAt","typeLabel":"string\u003cdate-time> | null"},"outcome":{"type":"object","description":"Orthogonal facts, never a prose string — a consumer should never have to sniff a string for what happened.","properties":{"answered":{"type":"boolean","uniqueKey":"outcome.answered","typeLabel":"boolean"},"connectedMs":{"type":"integer","uniqueKey":"outcome.connectedMs","typeLabel":"integer"},"endedBy":{"oneOf":[{"type":"string","enum":["caller","agent","system",null],"description":"`system` is one of our own limits firing (max duration, silence timeout). Null when the call was never answered and nothing in the trace said why.","uniqueKey":"outcome.endedBy.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","enum":["caller","agent","system",null],"description":"`system` is one of our own limits firing (max duration, silence timeout). Null when the call was never answered and nothing in the trace said why.","uniqueKey":"outcome.endedBy.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.endedBy","typeLabel":"enum\u003cstring> | null"},"endReason":{"oneOf":[{"type":"string","enum":["agent_ended","caller_hangup","carrier_dropped","transferred","voicemail_left","no_answer","busy","rejected","invalid_number","blocked_dnd","carrier_failed","max_duration","silence_timeout","pipeline_error",null],"description":"A fixed wire vocabulary, deliberately separate from the internal enum so a consumer's histogram does not shift when the internals are tidied. Two things that might be expected here are not: whether anyone picked up is `outcome.answered`, and a voicemail *detection* rides in `outcome.voicemail` — the call still ended for one of the reasons above. Null when nothing said why.","uniqueKey":"outcome.endReason.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","enum":["agent_ended","caller_hangup","carrier_dropped","transferred","voicemail_left","no_answer","busy","rejected","invalid_number","blocked_dnd","carrier_failed","max_duration","silence_timeout","pipeline_error",null],"description":"A fixed wire vocabulary, deliberately separate from the internal enum so a consumer's histogram does not shift when the internals are tidied. Two things that might be expected here are not: whether anyone picked up is `outcome.answered`, and a voicemail *detection* rides in `outcome.voicemail` — the call still ended for one of the reasons above. Null when nothing said why.","uniqueKey":"outcome.endReason.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.endReason","typeLabel":"enum\u003cstring> | null"},"error":{"oneOf":[{"type":"string","uniqueKey":"outcome.error.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"outcome.error.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.error","typeLabel":"string | null"},"voicemail":{"type":"object","description":"What the detector decided, not what one signal saw: the acoustic vote alone fires on humans too (a chatty callee's opening monologue trips it), so `detected` means the votes reached a decision.","properties":{"detected":{"type":"boolean","uniqueKey":"outcome.voicemail.detected","typeLabel":"boolean"},"confidence":{"type":"number","example":0.67,"description":"**Not a probability.** The detector votes, and this is how many of its signals agreed over the three it takes to be unanimous, capped at `1.0`: `0.67` is the ordinary two-vote decision, `1.0` is three or more, and `0.33` a confident LLM verdict deciding alone. `0` when nothing was detected.","uniqueKey":"outcome.voicemail.confidence","typeLabel":"number"},"signals":{"type":"array","items":{"type":"string","uniqueKey":"outcome.voicemail.signals.items.[INDEX]","typeLabel":"string"},"example":["acoustic","keyword"],"description":"Which independent signals agreed — the words behind `confidence`. Today one or more of `acoustic` (the far end monologued), `beep` (a record tone), `keyword` (greeting phrasing in the transcript) and `llm`. Deliberately not an enum: the detector has gained a signal before and will again, so match on the ones you care about rather than exhaustively.","uniqueKey":"outcome.voicemail.signals","typeLabel":"string[]"},"action":{"oneOf":[{"type":"string","enum":["hangup","leaveMessage",null],"description":"What the assistant was configured to do about a machine. Null when nothing was detected. `leaveMessage` here says the action ran; whether the message actually played is what separates `endReason: voicemail_left` from `agent_ended`.","uniqueKey":"outcome.voicemail.action.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","enum":["hangup","leaveMessage",null],"description":"What the assistant was configured to do about a machine. Null when nothing was detected. `leaveMessage` here says the action ran; whether the message actually played is what separates `endReason: voicemail_left` from `agent_ended`.","uniqueKey":"outcome.voicemail.action.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.voicemail.action","typeLabel":"enum\u003cstring> | null"}},"uniqueKey":"outcome.voicemail","typeLabel":"object"},"transfer":{"oneOf":[{"type":"object","description":"The transfer that actually happened, or null if none was attempted. A transfer is a sequence — requested, then resolved — and this reports the last one, so a warm attempt that failed and fell back to a cold one that completed reports the cold one.","properties":{"kind":{"type":"string","enum":["cold","warm"],"description":"Cold (a SIP REFER) unless the warm path ran.","uniqueKey":"outcome.transfer.oneOf.0.kind","typeLabel":"enum\u003cstring>"},"destination":{"oneOf":[{"type":"string","uniqueKey":"outcome.transfer.oneOf.0.destination.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"outcome.transfer.oneOf.0.destination.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.transfer.oneOf.0.destination","typeLabel":"string | null"},"result":{"oneOf":[{"type":"string","enum":["requested","completed","failed",null],"description":"`requested` means the attempt never resolved.","uniqueKey":"outcome.transfer.oneOf.0.result.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","enum":["requested","completed","failed",null],"description":"`requested` means the attempt never resolved.","uniqueKey":"outcome.transfer.oneOf.0.result.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.transfer.oneOf.0.result","typeLabel":"enum\u003cstring> | null"}},"uniqueKey":"outcome.transfer.oneOf.0","typeLabel":"object"},{"type":"null","description":"The transfer that actually happened, or null if none was attempted. A transfer is a sequence — requested, then resolved — and this reports the last one, so a warm attempt that failed and fell back to a cold one that completed reports the cold one.","properties":{"kind":{"type":"string","enum":["cold","warm"],"description":"Cold (a SIP REFER) unless the warm path ran."},"destination":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"string","enum":["requested","completed","failed",null],"description":"`requested` means the attempt never resolved."},{"type":"null","enum":["requested","completed","failed",null],"description":"`requested` means the attempt never resolved."}]}},"uniqueKey":"outcome.transfer.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.transfer","typeLabel":"object | null"},"callback":{"oneOf":[{"type":"object","description":"The callback the assistant promised on this call, or `null` if it promised none — branch on presence, not on a boolean. Already booked in Vodex when this fires, so no follow-up GET is needed.","properties":{"id":{"oneOf":[{"type":"string","format":"uuid","description":"The `scheduled_callbacks` row, for `GET /v1/callbacks/{id}`.","uniqueKey":"outcome.callback.oneOf.0.id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","format":"uuid","description":"The `scheduled_callbacks` row, for `GET /v1/callbacks/{id}`.","uniqueKey":"outcome.callback.oneOf.0.id.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.callback.oneOf.0.id","typeLabel":"string\u003cuuid> | null"},"at":{"type":"string","format":"date-time","description":"When the callback is due, as an instant.","uniqueKey":"outcome.callback.oneOf.0.at","typeLabel":"string\u003cdate-time>"},"timezone":{"oneOf":[{"type":"string","description":"IANA zone the caller was speaking in, when one was known.","uniqueKey":"outcome.callback.oneOf.0.timezone.oneOf.0","typeLabel":"string"},{"type":"null","description":"IANA zone the caller was speaking in, when one was known.","uniqueKey":"outcome.callback.oneOf.0.timezone.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.callback.oneOf.0.timezone","typeLabel":"string | null"},"note":{"oneOf":[{"type":"string","description":"What the caller asked to be called about.","uniqueKey":"outcome.callback.oneOf.0.note.oneOf.0","typeLabel":"string"},{"type":"null","description":"What the caller asked to be called about.","uniqueKey":"outcome.callback.oneOf.0.note.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.callback.oneOf.0.note","typeLabel":"string | null"},"assistantId":{"oneOf":[{"type":"string","description":"Assistant that will make the callback.","uniqueKey":"outcome.callback.oneOf.0.assistantId.oneOf.0","typeLabel":"string"},{"type":"null","description":"Assistant that will make the callback.","uniqueKey":"outcome.callback.oneOf.0.assistantId.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.callback.oneOf.0.assistantId","typeLabel":"string | null"},"rescheduled":{"type":"boolean","description":"True when this moved an existing promise rather than making a new one.","uniqueKey":"outcome.callback.oneOf.0.rescheduled","typeLabel":"boolean"}},"uniqueKey":"outcome.callback.oneOf.0","typeLabel":"object"},{"type":"null","description":"The callback the assistant promised on this call, or `null` if it promised none — branch on presence, not on a boolean. Already booked in Vodex when this fires, so no follow-up GET is needed.","properties":{"id":{"oneOf":[{"type":"string","format":"uuid","description":"The `scheduled_callbacks` row, for `GET /v1/callbacks/{id}`."},{"type":"null","format":"uuid","description":"The `scheduled_callbacks` row, for `GET /v1/callbacks/{id}`."}]},"at":{"type":"string","format":"date-time","description":"When the callback is due, as an instant."},"timezone":{"oneOf":[{"type":"string","description":"IANA zone the caller was speaking in, when one was known."},{"type":"null","description":"IANA zone the caller was speaking in, when one was known."}]},"note":{"oneOf":[{"type":"string","description":"What the caller asked to be called about."},{"type":"null","description":"What the caller asked to be called about."}]},"assistantId":{"oneOf":[{"type":"string","description":"Assistant that will make the callback."},{"type":"null","description":"Assistant that will make the callback."}]},"rescheduled":{"type":"boolean","description":"True when this moved an existing promise rather than making a new one."}},"uniqueKey":"outcome.callback.oneOf.1","typeLabel":"null"}],"uniqueKey":"outcome.callback","typeLabel":"object | null"},"direction":{"type":"string","uniqueKey":"outcome.direction","typeLabel":"string"}},"uniqueKey":"outcome","typeLabel":"object"},"transcript":{"type":"array","description":"Turn-level, with offsets in seconds from the first traced event.","items":{"type":"object","properties":{"role":{"type":"string","enum":["user","agent"],"uniqueKey":"transcript.items.[INDEX].role","typeLabel":"enum\u003cstring>"},"text":{"type":"string","uniqueKey":"transcript.items.[INDEX].text","typeLabel":"string"},"at":{"type":"number","uniqueKey":"transcript.items.[INDEX].at","typeLabel":"number"},"interrupted":{"type":"boolean","uniqueKey":"transcript.items.[INDEX].interrupted","typeLabel":"boolean"}},"uniqueKey":"transcript.items.[INDEX]","typeLabel":"object"},"uniqueKey":"transcript","typeLabel":"object[]"},"analysis":{"type":"object","description":"Open envelope — additive keys only. A handler written today keeps parsing tomorrow's payloads.","properties":{"summary":{"type":"string","uniqueKey":"analysis.summary","typeLabel":"string"},"sentiment":{"type":"object","uniqueKey":"analysis.sentiment","typeLabel":"object"},"structured":{"type":"object","description":"Per-assistant extraction (design 0018).","properties":{"outcome":{"type":"object","description":"Which of the assistant's own outcomes this conversation reached. Absent when the assistant defines none, when nobody answered, and on calls that predate the feature — all ordinary, none an error.\nDistinct from the top-level `outcome` above, which is the mechanical record of how the call ended. This one is about the conversation.","properties":{"key":{"type":"string","description":"Stable across renames — group reporting on this.","uniqueKey":"analysis.structured.outcome.key","typeLabel":"string"},"name":{"type":"string","description":"The wording in force when this call was classified.","uniqueKey":"analysis.structured.outcome.name","typeLabel":"string"},"rationale":{"type":"string","description":"One sentence on what decided it.","uniqueKey":"analysis.structured.outcome.rationale","typeLabel":"string"}},"uniqueKey":"analysis.structured.outcome","typeLabel":"object"}},"uniqueKey":"analysis.structured","typeLabel":"object"}},"uniqueKey":"analysis","typeLabel":"object"},"quality":{"type":"object","properties":{"turns":{"type":"integer","uniqueKey":"quality.turns","typeLabel":"integer"},"ttfaP50Ms":{"oneOf":[{"type":"number","uniqueKey":"quality.ttfaP50Ms.oneOf.0","typeLabel":"number"},{"type":"null","uniqueKey":"quality.ttfaP50Ms.oneOf.1","typeLabel":"null"}],"uniqueKey":"quality.ttfaP50Ms","typeLabel":"number | null"},"ttfaMaxMs":{"oneOf":[{"type":"number","uniqueKey":"quality.ttfaMaxMs.oneOf.0","typeLabel":"number"},{"type":"null","uniqueKey":"quality.ttfaMaxMs.oneOf.1","typeLabel":"null"}],"uniqueKey":"quality.ttfaMaxMs","typeLabel":"number | null"},"interruptions":{"type":"integer","uniqueKey":"quality.interruptions","typeLabel":"integer"},"fallbacks":{"type":"integer","uniqueKey":"quality.fallbacks","typeLabel":"integer"}},"uniqueKey":"quality","typeLabel":"object"},"cost":{"type":"object","properties":{"totalUsd":{"oneOf":[{"type":"number","uniqueKey":"cost.totalUsd.oneOf.0","typeLabel":"number"},{"type":"null","uniqueKey":"cost.totalUsd.oneOf.1","typeLabel":"null"}],"uniqueKey":"cost.totalUsd","typeLabel":"number | null"},"breakdown":{"oneOf":[{"type":"object","description":"Absent rather than zeroed — a consumer must be able to tell \"not computed\" from \"cost nothing\".","uniqueKey":"cost.breakdown.oneOf.0","typeLabel":"object"},{"type":"null","description":"Absent rather than zeroed — a consumer must be able to tell \"not computed\" from \"cost nothing\".","uniqueKey":"cost.breakdown.oneOf.1","typeLabel":"null"}],"uniqueKey":"cost.breakdown","typeLabel":"object | null"}},"uniqueKey":"cost","typeLabel":"object"},"artifacts":{"type":"object","description":"References, never bytes — audio is resolved through the authed API when a user presses play, so it never leaves its region unbidden.","properties":{"recording":{"oneOf":[{"type":"string","example":"vodex://recordings/call-…","uniqueKey":"artifacts.recording.oneOf.0","typeLabel":"string"},{"type":"null","example":"vodex://recordings/call-…","uniqueKey":"artifacts.recording.oneOf.1","typeLabel":"null"}],"uniqueKey":"artifacts.recording","typeLabel":"string | null"},"trace":{"type":"string","example":"vodex://traces/call-…","uniqueKey":"artifacts.trace","typeLabel":"string"},"region":{"oneOf":[{"type":"string","uniqueKey":"artifacts.region.oneOf.0","typeLabel":"string"},{"type":"null","uniqueKey":"artifacts.region.oneOf.1","typeLabel":"null"}],"uniqueKey":"artifacts.region","typeLabel":"string | null"}},"uniqueKey":"artifacts","typeLabel":"object"},"variables":{"type":"object","additionalProperties":{"type":"string","uniqueKey":"variables.additionalProperties","typeLabel":"string"},"description":"Exactly what the agent knew, frozen at call time — the assistant's config may have changed since.","uniqueKey":"variables","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"type":"interaction.completed","id":"\u003cstring>","tenantId":"3c90c3cc-0d44-4b50-8888-8dd25736052a","contactRef":"\u003cstring>","rawAddress":"\u003cstring>","direction":"\u003cstring>","from":"\u003cstring>","to":"\u003cstring>","assistantId":"\u003cstring>","engine":"\u003cstring>","startedAt":"2023-11-07T05:31:56Z","endedAt":"2023-11-07T05:31:56Z","outcome":{"answered":true,"connectedMs":123,"error":"\u003cstring>","voicemail":{"detected":true,"confidence":0.67,"signals":["acoustic","keyword"]},"transfer":{"destination":"\u003cstring>"},"callback":{"id":"3c90c3cc-0d44-4b50-8888-8dd25736052a","at":"2023-11-07T05:31:56Z","timezone":"\u003cstring>","note":"\u003cstring>","assistantId":"\u003cstring>","rescheduled":true},"direction":"\u003cstring>"},"transcript":[{"text":"\u003cstring>","at":123,"interrupted":true}],"analysis":{"summary":"\u003cstring>","sentiment":{},"structured":{"outcome":{"key":"\u003cstring>","name":"\u003cstring>","rationale":"\u003cstring>"}}},"quality":{"turns":123,"ttfaP50Ms":123,"ttfaMaxMs":123,"interruptions":123,"fallbacks":123},"cost":{"totalUsd":123,"breakdown":{}},"artifacts":{"recording":"vodex://recordings/call-…","trace":"vodex://traces/call-…","region":"\u003cstring>"},"variables":{}}}},"exampleType":"generated"}},"exampleType":"generated"},"responses":{"5f965f0d-4a59-4e90-9ed4-26cd65fc30a4":{"description":"Retried — a timeout is transient.","content":{"_mintlify/placeholder":{"schema":{"type":"object","description":""}}}},"73ee9e31-1e07-4ae5-a80f-78a9717ed844":{"description":"Retried, with the backoff below.","content":{"_mintlify/placeholder":{"schema":{"type":"object","description":""}}}},"ad86f00b-9108-487d-839e-288afad21a6a":{"description":"Acknowledged — the delivery is settled.","content":{"_mintlify/placeholder":{"schema":{"type":"object","description":""}}}},"fb0c11fa-b526-48ef-9d41-b1877267d3e4":{"description":"Retried, with the backoff below.","content":{"_mintlify/placeholder":{"schema":{"type":"object","description":""}}}},"762b5d3b-3c83-411c-9024-e3bbe3c8836c":{"description":"NOT retried. Any other 4xx is the consumer saying the request itself is wrong, and repeating it only burns the attempt budget a real outage needs.","content":{"_mintlify/placeholder":{"schema":{"type":"object","description":""}}}}},"security":{}}}}],"security":{"986b34dc-9d64-43d6-addf-8d27adc5ae4e":{"ApiKeyBearer":{"type":"http","scheme":"bearer","description":"Tenant API key (`vdx_live_…`) as `Authorization: Bearer`.","scopes":[],"schemeName":"ApiKeyBearer"}}},"servers":{"454f84ff-3690-4156-8c58-c64805db6548":{"url":"https://apiv2.vodex.ai/v1","description":"Production"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","description":"Tenant API key (`vdx_live_…`) as `Authorization: Bearer`.","scopes":[],"schemeName":"ApiKeyBearer"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"Tenant API key (`vdx_live_…`) as `Authorization: Bearer`.","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"ApiKeyBearer","name":"Authorization"}],"title":"ApiKeyBearer"}]},"originalFileLocation":"openapi/api-public-v1.yaml"},"subdomain":"vodex","siteName":"Vodex API","title":"Send an SMS - Vodex API","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-30T16:41:44.965Z","originalFileLocation":"api-reference/sms/send-an-sms.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Idempotency-Key is mandatory — retrying a timeout must never double-text anyone. Only a 201 is replayed; a validation failure or a provider rejection releases the key so a corrected retry can reuse it. The same key with a different body is 409, and a second request while the first is in flight is also 409. Every attempt that reaches the provider is logged, sent or failed — the row is the audit trail. A provider rejection is therefore a 502 that still carries the logged row\u0026#x27;s messageId. A successful send also enqueues an interaction.completed webhook with channel: \u0026quot;sms\u0026quot;, on the same stream as voice.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Vodex API\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Send an SMS - Vodex API\">\u003cmeta data-mint-head property=\"og:description\" content=\"Idempotency-Key is mandatory — retrying a timeout must never double-text anyone. Only a 201 is replayed; a validation failure or a provider rejection releases the key so a corrected retry can reuse it. The same key with a different body is 409, and a second request while the first is in flight is also 409. Every attempt that reaches the provider is logged, sent or failed — the row is the audit trail. A provider rejection is therefore a 502 that still carries the logged row\u0026#x27;s messageId. A successful send also enqueues an interaction.completed webhook with channel: \u0026quot;sms\u0026quot;, on the same stream as voice.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Vodex API\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://vodex.mintlify.app/_mintlify/api/og/v2?division=SMS\u0026amp;title=Send+an+SMS\u0026amp;description=%60Idempotency-Key%60+is+**mandatory**+%E2%80%94+retrying+a+timeout+must+never%0Adouble-text+anyone.+Only+a+%60201%60+is+replayed%3B+a+validation+failure+or+a%0Aprovider+rejection+**\u0026amp;theme=6d89815cfe9107c7cb0143e4\u0026amp;signature=ec632570ecf155622f98260c45ad60de024a250925c0707b30665c773eabf0e5\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Send an SMS - Vodex API\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Idempotency-Key is mandatory — retrying a timeout must never double-text anyone. Only a 201 is replayed; a validation failure or a provider rejection releases the key so a corrected retry can reuse it. The same key with a different body is 409, and a second request while the first is in flight is also 409. Every attempt that reaches the provider is logged, sent or failed — the row is the audit trail. A provider rejection is therefore a 502 that still carries the logged row\u0026#x27;s messageId. A successful send also enqueues an interaction.completed webhook with channel: \u0026quot;sms\u0026quot;, on the same stream as voice.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://vodex.mintlify.app/_mintlify/api/og/v2?division=SMS\u0026amp;title=Send+an+SMS\u0026amp;description=%60Idempotency-Key%60+is+**mandatory**+%E2%80%94+retrying+a+timeout+must+never%0Adouble-text+anyone.+Only+a+%60201%60+is+replayed%3B+a+validation+failure+or+a%0Aprovider+rejection+**\u0026amp;theme=6d89815cfe9107c7cb0143e4\u0026amp;signature=ec632570ecf155622f98260c45ad60de024a250925c0707b30665c773eabf0e5\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/vodex/lIjSc2yqSN3yLkge/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Vodex API\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#FF4D00\">\u003clink data-mint-head rel=\"canonical\" href=\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/sms/send-an-sms.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://apidocs.vodex.ai/#organization\",\"name\":\"Vodex API\",\"url\":\"https://apidocs.vodex.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/vodex/78No6_lqTF_DicwD/logo/vodex-full.svg?fit=max\u0026auto=format\u0026n=78No6_lqTF_DicwD\u0026q=85\u0026s=abc36083e47f9332141ac1141d1cbe4a\"}},{\"@type\":\"WebSite\",\"@id\":\"https://apidocs.vodex.ai#website\",\"name\":\"Vodex API\",\"url\":\"https://apidocs.vodex.ai\",\"publisher\":{\"@id\":\"https://apidocs.vodex.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms#webpage\",\"url\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms\",\"name\":\"Send an SMS\",\"description\":\"Idempotency-Key is mandatory — retrying a timeout must never double-text anyone. Only a 201 is replayed; a validation failure or a provider rejection releases the key so a corrected retry can reuse it. The same key with a different body is 409, and a second request while the first is in flight is also 409. Every attempt that reaches the provider is logged, sent or failed — the row is the audit trail. A provider rejection is therefore a 502 that still carries the logged row's messageId. A successful send also enqueues an interaction.completed webhook with channel: \\\"sms\\\", on the same stream as voice.\",\"dateModified\":\"2026-10-30T16:41:44.965Z\",\"isPartOf\":{\"@id\":\"https://apidocs.vodex.ai#website\"},\"breadcrumb\":{\"@id\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"SMS\",\"item\":\"https://apidocs.vodex.ai/api-reference/sms/sms-provider-capabilities\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Send an SMS\",\"item\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms#apireference\",\"headline\":\"Send an SMS\",\"name\":\"Send an SMS\",\"description\":\"Idempotency-Key is mandatory — retrying a timeout must never double-text anyone. Only a 201 is replayed; a validation failure or a provider rejection releases the key so a corrected retry can reuse it. The same key with a different body is 409, and a second request while the first is in flight is also 409. Every attempt that reaches the provider is logged, sent or failed — the row is the audit trail. A provider rejection is therefore a 502 that still carries the logged row's messageId. A successful send also enqueues an interaction.completed webhook with channel: \\\"sms\\\", on the same stream as voice.\",\"url\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms\",\"mainEntityOfPage\":{\"@id\":\"https://apidocs.vodex.ai/api-reference/sms/send-an-sms#webpage\"},\"dateModified\":\"2026-10-30T16:41:44.965Z\",\"publisher\":{\"@id\":\"https://apidocs.vodex.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://apidocs.vodex.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Vodex API\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Vodex API","nav":{"global":null,"tabs":[{"tab":"Documentation","pages":[{"title":"Documentation","href":"/introduction"}]},{"tab":"API Reference","groups":[{"group":"Assistants","pages":[{"title":"List assistants","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /console/assistants","href":"/api-reference/assistants/list-assistants"},{"title":"Create or replace an assistant","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /console/assistants","href":"/api-reference/assistants/create-or-replace-an-assistant"},{"title":"Fetch one assistant's full config","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /console/assistants/{id}","href":"/api-reference/assistants/fetch-one-assistants-full-config"},{"title":"Delete an assistant","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /console/assistants/{id}","href":"/api-reference/assistants/delete-an-assistant"},{"title":"List this assistant's outcomes","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /console/assistants/{id}/outcomes","href":"/api-reference/assistants/list-this-assistants-outcomes"},{"title":"Add an outcome","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /console/assistants/{id}/outcomes","href":"/api-reference/assistants/add-an-outcome"},{"title":"Remove an outcome","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /console/assistants/{id}/outcomes/{key}","href":"/api-reference/assistants/remove-an-outcome"},{"title":"Rename an outcome, or reword when it applies","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /console/assistants/{id}/outcomes/{key}","href":"/api-reference/assistants/rename-an-outcome-or-reword-when-it-applies"},{"title":"A CSV template for the survey importer","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /surveys/template.csv","href":"/api-reference/assistants/a-csv-template-for-the-survey-importer"},{"title":"Parse a survey CSV without saving it","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /console/assistants/{id}/survey.csv/preview","href":"/api-reference/assistants/parse-a-survey-csv-without-saving-it"},{"title":"Replace the assistant's questionnaire from a CSV","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /console/assistants/{id}/survey.csv","href":"/api-reference/assistants/replace-the-assistants-questionnaire-from-a-csv"},{"title":"Test a custom tool","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /console/tools/test","href":"/api-reference/assistants/test-a-custom-tool"}]},{"group":"Console","pages":[{"title":"The model catalog","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /console/catalog","href":"/api-reference/console/the-model-catalog"},{"title":"List voices","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /console/voices","href":"/api-reference/console/list-voices"},{"title":"Mint a LiveKit token for a web call","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /console/token","href":"/api-reference/console/mint-a-livekit-token-for-a-web-call"}]},{"group":"Usage","pages":[{"title":"Minute usage this period","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /usage","href":"/api-reference/usage/minute-usage-this-period"}]},{"group":"Calls","pages":[{"title":"List calls","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /calls","href":"/api-reference/calls/list-calls"},{"title":"Place an outbound call","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /calls","href":"/api-reference/calls/place-an-outbound-call"},{"title":"Fetch a call with its trace","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /calls/{id}","href":"/api-reference/calls/fetch-a-call-with-its-trace"},{"title":"Stream a call recording","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /recordings/{id}","href":"/api-reference/calls/stream-a-call-recording"}]},{"group":"Phone Numbers","pages":[{"title":"List numbers","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /phone-numbers","href":"/api-reference/phone-numbers/list-numbers"},{"title":"Add a number","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /phone-numbers","href":"/api-reference/phone-numbers/add-a-number"},{"title":"Remove a number","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /phone-numbers/{id}","href":"/api-reference/phone-numbers/remove-a-number"},{"title":"Reassign or relabel a number","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /phone-numbers/{id}","href":"/api-reference/phone-numbers/reassign-or-relabel-a-number"}]},{"group":"SIP Trunks","pages":[{"title":"List BYO SIP trunks","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /sip-trunks","href":"/api-reference/sip-trunks/list-byo-sip-trunks"},{"title":"Create a BYO SIP trunk","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sip-trunks","href":"/api-reference/sip-trunks/create-a-byo-sip-trunk"},{"title":"Delete a trunk","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /sip-trunks/{id}","href":"/api-reference/sip-trunks/delete-a-trunk"},{"title":"Update a SIP trunk","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /sip-trunks/{id}","href":"/api-reference/sip-trunks/update-a-sip-trunk"},{"title":"Rotate trunk credentials","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sip-trunks/{id}/rotate","href":"/api-reference/sip-trunks/rotate-trunk-credentials"}]},{"group":"Carriers","pages":[{"title":"The carrier registry","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /carriers","href":"/api-reference/carriers/the-carrier-registry"}]},{"group":"Integrations","pages":[{"title":"List connected carrier accounts","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /integrations","href":"/api-reference/integrations/list-connected-carrier-accounts"},{"title":"Connect a carrier account","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /integrations","href":"/api-reference/integrations/connect-a-carrier-account"},{"title":"One integration, with its numbers","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /integrations/{id}","href":"/api-reference/integrations/one-integration-with-its-numbers"},{"title":"Disconnect","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /integrations/{id}","href":"/api-reference/integrations/disconnect"},{"title":"Replace integration credentials","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /integrations/{id}/credentials","href":"/api-reference/integrations/replace-integration-credentials"},{"title":"Change how a gateway is dialed","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /integrations/{id}/gateway","href":"/api-reference/integrations/change-how-a-gateway-is-dialed"},{"title":"List available numbers","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /integrations/{id}/available-numbers","href":"/api-reference/integrations/list-available-numbers"},{"title":"Add numbers to an integration","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /integrations/{id}/numbers","href":"/api-reference/integrations/add-numbers-to-an-integration"}]},{"group":"Batches","pages":[{"title":"List batches","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /batches","href":"/api-reference/batches/list-batches"},{"title":"Create a batch","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches","href":"/api-reference/batches/create-a-batch"},{"title":"Fetch a batch","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /batches/{id}","href":"/api-reference/batches/fetch-a-batch"},{"title":"List rows","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /batches/{id}/rows","href":"/api-reference/batches/list-rows"},{"title":"Append rows","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/rows","href":"/api-reference/batches/append-rows"},{"title":"Check a CSV before creating anything","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/rows.csv/preview","href":"/api-reference/batches/check-a-csv-before-creating-anything"},{"title":"Append rows from a CSV","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/rows.csv","href":"/api-reference/batches/append-rows-from-a-csv"},{"title":"Cancel one row","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /batches/{id}/rows/{rowId}","href":"/api-reference/batches/cancel-one-row"},{"title":"Pause a running batch","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/pause","href":"/api-reference/batches/pause-a-running-batch"},{"title":"Resume a paused batch","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/resume","href":"/api-reference/batches/resume-a-paused-batch"},{"title":"Cancel a batch","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/cancel","href":"/api-reference/batches/cancel-a-batch"},{"title":"Requeue rows as a new run","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/restart","href":"/api-reference/batches/requeue-rows-as-a-new-run"},{"title":"The block plan","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /batches/{id}/blocks","href":"/api-reference/batches/the-block-plan"},{"title":"Resize a block","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /batches/{id}/blocks/{blockNo}","href":"/api-reference/batches/resize-a-block"},{"title":"Dial the next block","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /batches/{id}/blocks/next","href":"/api-reference/batches/dial-the-next-block"},{"title":"List dial attempts","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /batches/{id}/attempts","href":"/api-reference/batches/list-dial-attempts"}]},{"group":"Callbacks","pages":[{"title":"List callbacks","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /callbacks","href":"/api-reference/callbacks/list-callbacks"},{"title":"One callback","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /callbacks/{id}","href":"/api-reference/callbacks/one-callback"},{"title":"Update a callback","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /callbacks/{id}","href":"/api-reference/callbacks/update-a-callback"},{"title":"Let campaigns call a number again","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /callbacks/{id}/release","href":"/api-reference/callbacks/let-campaigns-call-a-number-again"}]},{"group":"Reports","pages":[{"title":"List reports","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /reports","href":"/api-reference/reports/list-reports"},{"title":"Create a report","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /reports","href":"/api-reference/reports/create-a-report"},{"title":"One report","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /reports/{id}","href":"/api-reference/reports/one-report"},{"title":"Delete a report","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /reports/{id}","href":"/api-reference/reports/delete-a-report"},{"title":"Update a report","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /reports/{id}","href":"/api-reference/reports/update-a-report"}]},{"group":"Number Rotation","pages":[{"title":"Per-number spacing, caps, and cooldown","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /number-rotation","href":"/api-reference/number-rotation/per-number-spacing-caps-and-cooldown"},{"title":"Set rotation for one number","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /number-rotation/{e164}","href":"/api-reference/number-rotation/set-rotation-for-one-number"}]},{"group":"Payments","pages":[{"title":"List payment attempts","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /payments","href":"/api-reference/payments/list-payment-attempts"},{"title":"Get a payment attempt","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /payments/{id}","href":"/api-reference/payments/get-a-payment-attempt"},{"title":"The workspace's payment carrier","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /payment-carriers/twilio-stripe","href":"/api-reference/payments/the-workspaces-payment-carrier"},{"title":"Set up or change the payment carrier","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /payment-carriers/twilio-stripe","href":"/api-reference/payments/set-up-or-change-the-payment-carrier"},{"title":"Remove the payment carrier","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /payment-carriers/twilio-stripe","href":"/api-reference/payments/remove-the-payment-carrier"},{"title":"Numbers in the Twilio account that could be Pay numbers","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /payment-carriers/twilio-stripe/available-numbers","href":"/api-reference/payments/numbers-in-the-twilio-account-that-could-be-pay-numbers"},{"title":"Choose the workspace's Pay numbers","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /payment-carriers/twilio-stripe/numbers","href":"/api-reference/payments/choose-the-workspaces-pay-numbers"},{"title":"Point a Pay number at the payment webhook","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /payment-carriers/twilio-stripe/numbers/{e164}/webhook","href":"/api-reference/payments/point-a-pay-number-at-the-payment-webhook"}]},{"group":"SMS","pages":[{"title":"SMS provider capabilities","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /sms/capabilities","href":"/api-reference/sms/sms-provider-capabilities"},{"title":"Store provider credentials","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /sms/providers/{provider}","href":"/api-reference/sms/store-provider-credentials"},{"title":"Remove provider credentials","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /sms/providers/{provider}","href":"/api-reference/sms/remove-provider-credentials"},{"title":"List SMS configurations","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /sms/configurations","href":"/api-reference/sms/list-sms-configurations"},{"title":"Create an SMS configuration","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sms/configurations","href":"/api-reference/sms/create-an-sms-configuration"},{"title":"Delete an SMS configuration","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /sms/configurations/{id}","href":"/api-reference/sms/delete-an-sms-configuration"},{"title":"Update an SMS configuration","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /sms/configurations/{id}","href":"/api-reference/sms/update-an-sms-configuration"},{"title":"List SMS senders","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /sms/senders","href":"/api-reference/sms/list-sms-senders"},{"title":"Provider content templates","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /sms/templates","href":"/api-reference/sms/provider-content-templates"},{"title":"Render exactly what a send would produce","description":"The **same** resolution the send path runs, minus the provider call — so\nthe confirm modal and the send cannot drift.\n\n`missingVariables` is the point of the endpoint: the renderer strips\nunmatched tokens contractually (raw `{{…}}` must never reach a handset),\nso this list is what lets the console warn instead of silently texting a\nblank. Token lookup is case-insensitive and accepts `{{key}}` and `{key}`;\na key spelled exactly as the token wins over one that differs only in\ncase. A token the variables leave empty is worked out as in the prompt:\n`{{full_name}}` from `first_name` and `last_name`, and expressions such\nas `{{ amount + 25 }}`. A date such as `{{today}}` needs a `tz` (or\n`timezone`) variable: without one it is stripped and listed as `tz`,\nnever sent in UTC. Anything else that cannot be worked out is listed\nwith the reason, e.g. `full_name (needs first_name)`.\n","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sms/preview","href":"/api-reference/sms/render-exactly-what-a-send-would-produce"},{"title":"Send an SMS","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /sms","href":"/api-reference/sms/send-an-sms"},{"title":"Message log","description":null,"deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /sms/messages","href":"/api-reference/sms/message-log"}]},{"group":"Webhooks","pages":[{"title":"Read the tenant's webhook endpoint","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /webhook-config","href":"/api-reference/webhooks/read-the-tenants-webhook-endpoint"},{"title":"Set the webhook endpoint","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /webhook-config","href":"/api-reference/webhooks/set-the-webhook-endpoint"},{"title":"Stop deliveries","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /webhook-config","href":"/api-reference/webhooks/stop-deliveries"},{"title":"Rotate the signing secret","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /signing-secret/rotate","href":"/api-reference/webhooks/rotate-the-signing-secret"},{"title":"Rotate the signing secret (alias)","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /webhook-config/rotate-secret","href":"/api-reference/webhooks/rotate-the-signing-secret-alias"},{"title":"Delivery records","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /webhook-deliveries","href":"/api-reference/webhooks/delivery-records"},{"title":"Fetch a delivery","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /webhook-deliveries/{id}","href":"/api-reference/webhooks/fetch-a-delivery"},{"title":"Resend a delivery","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /webhook-deliveries/{id}/resend","href":"/api-reference/webhooks/resend-a-delivery"}]},{"group":"Tenants","pages":[{"title":"Read this customer's retention period","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /retention","href":"/api-reference/tenants/read-this-customers-retention-period"},{"title":"Set this customer's retention period","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /retention","href":"/api-reference/tenants/set-this-customers-retention-period"},{"title":"Read recording retention","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /tenants/retention","href":"/api-reference/tenants/read-recording-retention"},{"title":"Set this tenant's recording retention","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /tenants/{id}/retention","href":"/api-reference/tenants/set-this-tenants-recording-retention"},{"title":"Fall back to the bucket default","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /tenants/{id}/retention","href":"/api-reference/tenants/fall-back-to-the-bucket-default"}]},{"group":"Contacts","pages":[{"title":"List contacts","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/accounts","href":"/api-reference/contacts/list-contacts"},{"title":"Create a contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/accounts","href":"/api-reference/contacts/create-a-contact"},{"title":"Fetch one contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/accounts/{id}","href":"/api-reference/contacts/fetch-one-contact"},{"title":"Delete a contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/accounts/{id}","href":"/api-reference/contacts/delete-a-contact"},{"title":"Update a contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/accounts/{id}","href":"/api-reference/contacts/update-a-contact"},{"title":"Delete many contacts at once","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/accounts/bulk-delete","href":"/api-reference/contacts/delete-many-contacts-at-once"},{"title":"Add a phone number or email to a contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/accounts/{id}/channels","href":"/api-reference/contacts/add-a-phone-number-or-email-to-a-contact"},{"title":"Remove a channel","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/accounts/{id}/channels/{channelId}","href":"/api-reference/contacts/remove-a-channel"},{"title":"Update a channel","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/accounts/{id}/channels/{channelId}","href":"/api-reference/contacts/update-a-channel"},{"title":"Everything that has happened to this contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/accounts/{id}/timeline","href":"/api-reference/contacts/everything-that-has-happened-to-this-contact"},{"title":"Consent, local time, and attempt counts","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/accounts/{id}/compliance","href":"/api-reference/contacts/consent-local-time-and-attempt-counts"},{"title":"Record the consent basis","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /contacts/accounts/{id}/compliance","href":"/api-reference/contacts/record-the-consent-basis"},{"title":"List custom attribute definitions","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/attributes","href":"/api-reference/contacts/list-custom-attribute-definitions"},{"title":"Define a custom attribute","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/attributes","href":"/api-reference/contacts/define-a-custom-attribute"},{"title":"Delete an attribute definition","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/attributes/{id}","href":"/api-reference/contacts/delete-an-attribute-definition"},{"title":"Rename, re-option, or archive an attribute","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/attributes/{id}","href":"/api-reference/contacts/rename-re-option-or-archive-an-attribute"},{"title":"List a contact's files","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/accounts/{id}/files","href":"/api-reference/contacts/list-a-contacts-files"},{"title":"Attach a file to a contact","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/accounts/{id}/files","href":"/api-reference/contacts/attach-a-file-to-a-contact"},{"title":"Download a file","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/files/{fileId}","href":"/api-reference/contacts/download-a-file"},{"title":"Delete a file","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/files/{fileId}","href":"/api-reference/contacts/delete-a-file"},{"title":"Past imports","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/imports","href":"/api-reference/contacts/past-imports"},{"title":"Import contacts from a CSV","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/imports","href":"/api-reference/contacts/import-contacts-from-a-csv"},{"title":"A CSV template with the recognised headers","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/imports/template","href":"/api-reference/contacts/a-csv-template-with-the-recognised-headers"},{"title":"One import's receipt","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/imports/{id}","href":"/api-reference/contacts/one-imports-receipt"},{"title":"Tenant contact settings","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/settings","href":"/api-reference/contacts/tenant-contact-settings"},{"title":"Choose which detail tabs to show, and in what order","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /contacts/settings","href":"/api-reference/contacts/choose-which-detail-tabs-to-show-and-in-what-order"},{"title":"The tab registry, and which are enabled","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/tabs","href":"/api-reference/contacts/the-tab-registry-and-which-are-enabled"}]},{"group":"Do Not Contact","pages":[{"title":"The suppression list","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/dnc","href":"/api-reference/do-not-contact/the-suppression-list"},{"title":"Suppress one address","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/dnc","href":"/api-reference/do-not-contact/suppress-one-address"},{"title":"Ask whether addresses are suppressed","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/dnc/check","href":"/api-reference/do-not-contact/ask-whether-addresses-are-suppressed"},{"title":"Upload a suppression list","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/dnc/import","href":"/api-reference/do-not-contact/upload-a-suppression-list"},{"title":"Lift a suppression","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/dnc/{id}","href":"/api-reference/do-not-contact/lift-a-suppression"},{"title":"Correct an entry's value or reason","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/dnc/{id}","href":"/api-reference/do-not-contact/correct-an-entrys-value-or-reason"},{"title":"The person-level decision, and which of their addresses are suppressed","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/accounts/{id}/dnc","href":"/api-reference/do-not-contact/the-person-level-decision-and-which-of-their-addresses-are-suppressed"},{"title":"Mark a person do-not-contact, or clear it","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml put /contacts/accounts/{id}/dnc","href":"/api-reference/do-not-contact/mark-a-person-do-not-contact-or-clear-it"}]},{"group":"Audiences","pages":[{"title":"List audiences","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/audiences","href":"/api-reference/audiences/list-audiences"},{"title":"Save a filter as an audience","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/audiences","href":"/api-reference/audiences/save-a-filter-as-an-audience"},{"title":"The fields a filter may reach, and their comparators","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/audiences/fields","href":"/api-reference/audiences/the-fields-a-filter-may-reach-and-their-comparators"},{"title":"Count and sample who a filter matches","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/audiences/preview","href":"/api-reference/audiences/count-and-sample-who-a-filter-matches"},{"title":"Fetch one audience","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/audiences/{id}","href":"/api-reference/audiences/fetch-one-audience"},{"title":"Delete an audience","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/audiences/{id}","href":"/api-reference/audiences/delete-an-audience"},{"title":"Rename an audience or change its filter","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/audiences/{id}","href":"/api-reference/audiences/rename-an-audience-or-change-its-filter"},{"title":"Who is in an audience right now","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/audiences/{id}/members","href":"/api-reference/audiences/who-is-in-an-audience-right-now"}]},{"group":"Campaigns","pages":[{"title":"List campaigns","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/campaigns","href":"/api-reference/campaigns/list-campaigns"},{"title":"Create a campaign","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns","href":"/api-reference/campaigns/create-a-campaign"},{"title":"What a prompt variable can be filled from","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/campaigns/variable-sources","href":"/api-reference/campaigns/what-a-prompt-variable-can-be-filled-from"},{"title":"The source each prompt variable name-matches to","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/resolve-variables","href":"/api-reference/campaigns/the-source-each-prompt-variable-name-matches-to"},{"title":"Delete many campaigns at once","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/bulk-delete","href":"/api-reference/campaigns/delete-many-campaigns-at-once"},{"title":"Fetch one campaign","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml get /contacts/campaigns/{id}","href":"/api-reference/campaigns/fetch-one-campaign"},{"title":"Delete a campaign","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml delete /contacts/campaigns/{id}","href":"/api-reference/campaigns/delete-a-campaign"},{"title":"Edit a campaign that has not launched","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/campaigns/{id}","href":"/api-reference/campaigns/edit-a-campaign-that-has-not-launched"},{"title":"Change a running campaign, safely","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml patch /contacts/campaigns/{id}/live","href":"/api-reference/campaigns/change-a-running-campaign-safely"},{"title":"Turn the audience into calls","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/{id}/launch","href":"/api-reference/campaigns/turn-the-audience-into-calls"},{"title":"Dial the next block","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/{id}/runs/next","href":"/api-reference/campaigns/dial-the-next-block"},{"title":"Pause a running campaign","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/{id}/pause","href":"/api-reference/campaigns/pause-a-running-campaign"},{"title":"Resume a paused campaign","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/{id}/resume","href":"/api-reference/campaigns/resume-a-paused-campaign"},{"title":"Stop a campaign for good","deprecated":null,"version":null,"openapi":"/openapi/api-public-v1.yaml post /contacts/campaigns/{id}/stop","href":"/api-reference/campaigns/stop-a-campaign-for-good"}]}]}]},"basePath":"","title":"Send an SMS - Vodex API","buildId":"dpl_DeHjVRGfFnhYQwHnfC2pjeXXv8h9","deploymentId":"dpl_DeHjVRGfFnhYQwHnfC2pjeXXv8h9","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-CS552b7R.js","utils-DDTCYAF2.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-De8ttokP.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-DrwRDvAh.js","snippetPresets-DtAN0nWx.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-D5rWArI6.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-O2i12wsz.js","shallow-DV8xABTt.js","getApiPlaygroundDisplay-DBZ0B5Jx.js","CodeSnippet-BVi0tPUX.js","CodeSnippets-CqASbIwY.js","Page-m07pfKpT.js","getPastedJson-DG9vsMS8.js","icon-CXzRSCr8.js","MethodPill-BdKVtEuX.js","DuplicateIcon-CZlmBrJI.js","createIcon-biFEUKPL.js","DynamicMarkdown-B54_zNBF.js","SectionHeading-DwwHK3Pt.js","axios-vUo_bRtp.js","Markdown-DfhCTwyA.js","clsx-xpJZXxdP.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-BTZUMDnx.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-DqdKa2R4.js"]}