{"openapi":"3.1.0","info":{"title":"VoiceLayer API","version":"1.0.0","description":"Send and receive messages on SMS, WhatsApp, Telegram, Discord and email from one API, follow conversations, hand them between your code, your AI agent and people, and hear about everything through webhooks or an event stream.\n\nAuthenticate every request with a secret API key: `Authorization: Bearer $VOICELAYER_API_KEY`. Create keys in the dashboard under **Developers → API keys**. A test key (`vl_test_…`) runs every check without reaching a real carrier and costs nothing.\n\nErrors answer a JSON body with an `error` code, a `message`, a `requestId`, whether it is `retryable`, and a `docs` link to the code's page."},"servers":[{"url":"https://api.vlayers.ai"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"A secret API key from the dashboard (Developers → API keys): `vl_live_…`, or `vl_test_…` for test mode. Each operation says which scope the key needs."}},"schemas":{"MessagingError":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_idempotency_key","unauthorized","insufficient_scope","no_project","sms_refused","wallet_refused","not_found","capability_not_ready","recipient_opted_out","idempotency_conflict","window_closed","controller_conflict","controller_unsupported","channel_not_priced","channel_not_supported","not_linkable","number_inactive","plugin_suspended","outcome_unknown","send_in_progress","content_too_long","media_too_large","media_unavailable","operation_not_supported","output_refused","rate_limited","channel_not_registered","trust_unavailable","wallet_unavailable","messaging_unavailable","provider_error","provider_retry_later","no_sender","sender_ambiguous","recipient_not_allowed","test_mode_only","test_address_required","test_address_not_allowed","test_limit_reached"]},"message":{"type":"string"},"requestId":{"type":"string"},"retryable":{"type":"boolean"},"details":{"type":"object","additionalProperties":{}},"docs":{"type":"string","format":"uri"}},"required":["error","message","requestId","retryable","docs"]},"PublicMessage":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"channel":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["queued","sent","delivered","read","failed","received"]},"text":{"type":["string","null"]},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"contentType":{"type":["string","null"]}},"required":["url","contentType"]}},"from":{"type":["string","null"]},"to":{"type":["string","null"]},"bindingId":{"type":["string","null"],"format":"uuid"},"metadata":{"type":"object","additionalProperties":{}},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":["string","null"]}},"required":["code","message"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","conversationId","channel","direction","status","text","media","from","to","bindingId","metadata","error","createdAt"]},"PublicConversation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channel":{"type":"string"},"lineId":{"type":"string","format":"uuid"},"bindingId":{"type":["string","null"],"format":"uuid"},"peer":{"type":"object","properties":{"address":{"type":["string","null"]}},"required":["address"]},"controller":{"type":"string","enum":["agent","api","human"]},"status":{"type":"string"},"openedAt":{"type":"string","format":"date-time"},"lastActivityAt":{"type":"string","format":"date-time"},"test":{"type":"boolean"},"window":{"type":"object","properties":{"open":{"type":"boolean"},"closesAt":{"type":["string","null"]}},"required":["open","closesAt"]}},"required":["id","channel","lineId","bindingId","peer","controller","status","openedAt","lastActivityAt","test"]},"PublicEventEnvelope":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["message.received","message.sent","message.delivered","message.failed","conversation.created","conversation.controller_changed"]},"createdAt":{"type":"string","format":"date-time"},"livemode":{"type":"boolean","default":true},"data":{"type":"object","additionalProperties":{}}},"required":["id","type","createdAt","data"]}},"parameters":{}},"paths":{"/v1/messages":{"post":{"operationId":"sendMessage","summary":"Send a message","tags":["messages"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:send"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":255},"required":false,"description":"A unique value (a UUID works) that makes a retry safe: sending the same key again returns the first result instead of acting twice. 1–255 printable characters.","name":"idempotency-key","in":"header","example":"7f3c9a2e-5b1d-4c8e-9f0a-2d6b8e4c1a37"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","minLength":1,"maxLength":64,"description":"The channel to send on: `sms`, `mms`, `whatsapp`, `telegram`, `discord` or `email`. `GET /v1/channels` lists what your workspace can use."},"from":{"anyOf":[{"type":"object","properties":{"phoneNumberId":{"type":"string","format":"uuid"}},"required":["phoneNumberId"],"additionalProperties":false},{"type":"object","properties":{"bindingId":{"type":"string","format":"uuid"}},"required":["bindingId"],"additionalProperties":false},{"type":"object","properties":{"mailboxId":{"type":"string","minLength":3,"maxLength":320}},"required":["mailboxId"],"additionalProperties":false}],"description":"Which of your senders to use: `{ \"phoneNumberId\" }` for SMS and MMS, `{ \"bindingId\" }` for WhatsApp, Telegram and Discord, `{ \"mailboxId\" }` for email. Leave it out when you have one sender on the channel."},"to":{"anyOf":[{"type":"string","minLength":1,"maxLength":320},{"type":"object","properties":{"conversationId":{"type":"string","format":"uuid"}},"required":["conversationId"],"additionalProperties":false}],"description":"Who receives it: a phone number in E.164 format (`+14155550123`), the person's address on an app channel, an email address, or `{ \"conversationId\" }` to answer an existing conversation."},"content":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string","minLength":1,"maxLength":16000}},"required":["type","text"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["media"]},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri"}},"required":["url"],"additionalProperties":false},"minItems":1,"maxItems":10},"caption":{"type":"string","minLength":1,"maxLength":1600}},"required":["type","media"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["template"]},"template":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":512},"language":{"type":"string","minLength":2,"maxLength":35},"variables":{"type":"object","additionalProperties":{"type":"string","maxLength":1024}}},"required":["name"],"additionalProperties":false}},"required":["type","template"],"additionalProperties":false}],"description":"What to send: `{ \"type\": \"text\", \"text\" }`, `{ \"type\": \"media\", \"media\": [{ \"url\" }], \"caption\" }` (MMS). `{ \"type\": \"template\", \"template\" }` is reserved for message templates, which are not available yet: it is refused with `422 operation_not_supported`."},"subject":{"type":"string","minLength":1,"maxLength":200,"description":"Email only: the subject of a new email. A reply keeps its thread's subject."},"split":{"type":"string","enum":["auto","refuse"],"default":"auto","description":"`auto` (the default) sends a text longer than the channel allows as several messages, each billed. `refuse` answers `422 content_too_long` instead."},"metadata":{"type":"object","additionalProperties":{},"description":"Your own key/value pairs, up to 4 KB of JSON. Stored with the message and repeated in its events, so you can match an event to your records."}},"required":["channel","to","content"],"additionalProperties":false},"example":{"channel":"sms","to":"+15550123","content":{"type":"text","text":"Your table for two is booked for 7pm."}}}}},"responses":{"202":{"description":"Accepted: the first part is the message; `parts` lists every provider message","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"channel":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["queued","sent","delivered","read","failed","received"]},"text":{"type":["string","null"]},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"contentType":{"type":["string","null"]}},"required":["url","contentType"]}},"from":{"type":["string","null"]},"to":{"type":["string","null"]},"bindingId":{"type":["string","null"],"format":"uuid"},"metadata":{"type":"object","additionalProperties":{}},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":["string","null"]}},"required":["code","message"]},"createdAt":{"type":"string","format":"date-time"},"parts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","sent","delivered","read","failed","received"]}},"required":["id","status"]},"minItems":1}},"required":["id","conversationId","channel","direction","status","text","media","from","to","bindingId","metadata","error","createdAt","parts"]}},"required":["message"]},"example":{"message":{"id":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","direction":"outbound","status":"queued","text":"Your table for two is booked for 7pm.","media":[],"from":"+14155550100","to":"+15550123","bindingId":null,"metadata":{},"error":null,"createdAt":"2026-10-20T15:04:05.000Z","parts":[{"id":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","status":"queued"}]}}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"402":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"404":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"409":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"413":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"422":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"429":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"502":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}},"description":"Sends a text or media message on any channel your workspace has connected: SMS, WhatsApp, Telegram, Discord or email. Use it to start a conversation or to message an address directly; to answer someone, `POST /v1/conversations/{id}/messages` is simpler.\n\nThe answer is `202 Accepted`: the message is queued, not delivered yet. Delivery arrives as `message.sent`, `message.delivered` or `message.failed` events. Send an `Idempotency-Key` so a retry never sends twice.\n\nRequires an API key with the `messages:send` scope."},"get":{"operationId":"listMessages","summary":"List messages","tags":["messages"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:read"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"conversationId","in":"query","description":"Only messages in this conversation.","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"},{"schema":{"type":"string","minLength":1,"maxLength":64},"required":false,"name":"channel","in":"query","description":"Only messages on this channel.","example":"sms"},{"schema":{"type":"string","enum":["inbound","outbound"]},"required":false,"name":"direction","in":"query","description":"`inbound` (people writing to you) or `outbound` (what you sent).","example":"inbound"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"after","in":"query","description":"A page's `nextCursor`: return what came after it. Use it to poll for new messages.","example":"eyJjIjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"description":"A page's `prevCursor`: return what came before it. Pass `end` for the newest page.","name":"before","in":"query","example":"end"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query","description":"How many items to return, 1–100. Default 50.","example":20}],"responses":{"200":{"description":"A page of messages, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/PublicMessage"}},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"},"prevCursor":{"type":["string","null"]}},"required":["messages","nextCursor","hasMore","prevCursor"]},"example":{"messages":[{"id":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","direction":"inbound","status":"received","text":"Do you have a table for two tonight?","media":[],"from":"+15550123","to":"+14155550100","bindingId":null,"metadata":{},"error":null,"createdAt":"2026-10-20T15:04:05.000Z"}],"nextCursor":"eyJjIjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ","hasMore":false,"prevCursor":null}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}},"description":"Returns messages across your workspace, oldest first, filtered by conversation, channel or direction. Use it to backfill history or to poll for new messages with `after`; for real-time delivery, prefer webhooks or the event stream.\n\nRequires an API key with the `messages:read` scope."}},"/v1/conversations":{"get":{"operationId":"listConversations","summary":"List conversations","tags":["conversations"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:read"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"required":false,"name":"channel","in":"query","description":"Only conversations on this channel.","example":"whatsapp"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"bindingId","in":"query","description":"Only conversations on this sender (a connected WhatsApp, Telegram or Discord account).","example":"0192f5a9-2b3c-7d4e-9f5a-6b7c8d9e0f12"},{"schema":{"type":"string","enum":["agent","api","human"]},"required":false,"name":"controller","in":"query","description":"Only conversations answered by `agent`, `api` (your code) or `human`.","example":"human"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"updatedAfter","in":"query","description":"Only conversations with activity after this time (ISO 8601).","example":"2026-10-20T00:00:00.000Z"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"cursor","in":"query","description":"The previous page's `nextCursor`.","example":"eyJ1IjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query","description":"How many items to return, 1–100. Default 50.","example":20}],"responses":{"200":{"description":"A page of conversations","content":{"application/json":{"schema":{"type":"object","properties":{"conversations":{"type":"array","items":{"$ref":"#/components/schemas/PublicConversation"}},"nextCursor":{"type":["string","null"]}},"required":["conversations","nextCursor"]},"example":{"conversations":[{"id":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","lineId":"0192f5a8-1a2b-7c3d-8e4f-5a6b7c8d9e01","bindingId":null,"peer":{"address":"+15550123"},"controller":"api","status":"open","openedAt":"2026-10-20T15:04:05.000Z","lastActivityAt":"2026-10-20T15:04:05.000Z","test":true}],"nextCursor":null}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}},"description":"Returns the conversations in your workspace, most recently active first. Filter by channel, sender or controller — for example `controller=human` lists the conversations waiting for a person.\n\nRequires an API key with the `messages:read` scope."}},"/v1/conversations/{id}":{"get":{"operationId":"getConversation","summary":"Retrieve a conversation","tags":["conversations"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:read"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The conversation id.","name":"id","in":"path","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"}],"responses":{"200":{"description":"The conversation, with `window` on a windowed channel","content":{"application/json":{"schema":{"type":"object","properties":{"conversation":{"$ref":"#/components/schemas/PublicConversation"}},"required":["conversation"]},"example":{"conversation":{"id":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","lineId":"0192f5a8-1a2b-7c3d-8e4f-5a6b7c8d9e01","bindingId":null,"peer":{"address":"+15550123"},"controller":"api","status":"open","openedAt":"2026-10-20T15:04:05.000Z","lastActivityAt":"2026-10-20T15:04:05.000Z","test":true}}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"404":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}},"description":"Returns one conversation: its channel, the person it is with, who answers it (`controller`) and, on WhatsApp, whether the 24-hour reply window is open (`window`). Check `window.open` before replying on WhatsApp.\n\nRequires an API key with the `messages:read` scope."},"patch":{"operationId":"updateConversation","summary":"Hand off a conversation","description":"Changes who answers a conversation's incoming messages: `agent` (your VoiceLayer agent replies), `api` (your code replies) or `human` (a person replies from the dashboard). Use it to escalate to a person, or to take a conversation over from the agent. Each change emits one `conversation.controller_changed` event.\n\nPass `expectedController` to change it only if nobody else already has: otherwise the request is refused with `409 controller_conflict`.\n\nRequires an API key with the `conversations:control` scope.","tags":["conversations"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["conversations:control"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The conversation id.","name":"id","in":"path","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"},{"schema":{"type":"string","minLength":1,"maxLength":255},"required":false,"description":"A unique value (a UUID works) that makes a retry safe: sending the same key again returns the first result instead of acting twice. 1–255 printable characters.","name":"idempotency-key","in":"header","example":"7f3c9a2e-5b1d-4c8e-9f0a-2d6b8e4c1a37"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"controller":{"type":"string","enum":["agent","api","human"],"description":"Who answers from now on: `agent`, `api` or `human`."},"reason":{"type":"string","minLength":1,"maxLength":500,"description":"Why, in a sentence. Shown to the person who takes over and recorded in the event."},"expectedController":{"type":"string","enum":["agent","api","human"],"description":"Change it only if this is the current controller. Use it to avoid two handoffs racing each other."}},"required":["controller"],"additionalProperties":false},"example":{"controller":"human","reason":"The customer asked for a refund.","expectedController":"agent"}}}},"responses":{"200":{"description":"The conversation after the change","content":{"application/json":{"schema":{"type":"object","properties":{"conversation":{"$ref":"#/components/schemas/PublicConversation"},"changed":{"type":"boolean"}},"required":["conversation","changed"]},"example":{"conversation":{"id":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","lineId":"0192f5a8-1a2b-7c3d-8e4f-5a6b7c8d9e01","bindingId":null,"peer":{"address":"+15550123"},"controller":"human","status":"open","openedAt":"2026-10-20T15:04:05.000Z","lastActivityAt":"2026-10-20T15:04:05.000Z","test":true},"changed":true}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"404":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"409":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}}}},"/v1/conversations/{id}/messages":{"get":{"operationId":"listConversationMessages","summary":"List a conversation's messages","tags":["conversations"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:read"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The conversation id.","name":"id","in":"path","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"name":"after","in":"query","description":"A page's `nextCursor`: return what came after it. Use it to poll for new messages.","example":"eyJjIjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"description":"A page's `prevCursor`: return what came before it. Pass `end` for the newest page.","name":"before","in":"query","example":"end"},{"schema":{"type":"integer","minimum":1,"maximum":100},"required":false,"name":"limit","in":"query","description":"How many items to return, 1–100. Default 50.","example":20}],"responses":{"200":{"description":"A page of the conversation's messages","content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/PublicMessage"}},"nextCursor":{"type":["string","null"]},"hasMore":{"type":"boolean"},"prevCursor":{"type":["string","null"]}},"required":["messages","nextCursor","hasMore","prevCursor"]},"example":{"messages":[{"id":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","direction":"inbound","status":"received","text":"Do you have a table for two tonight?","media":[],"from":"+15550123","to":"+14155550100","bindingId":null,"metadata":{},"error":null,"createdAt":"2026-10-20T15:04:05.000Z"}],"nextCursor":"eyJjIjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ","hasMore":false,"prevCursor":null}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"404":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}},"description":"Returns one conversation's messages, oldest first. Pass `before=end` for the newest page, then each page's `prevCursor` as `before` to go further back — the usual way to show a chat history.\n\nRequires an API key with the `messages:read` scope."},"post":{"operationId":"replyToConversation","summary":"Reply in a conversation","tags":["conversations"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:send"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The conversation id.","name":"id","in":"path","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"},{"schema":{"type":"string","minLength":1,"maxLength":255},"required":false,"description":"A unique value (a UUID works) that makes a retry safe: sending the same key again returns the first result instead of acting twice. 1–255 printable characters.","name":"idempotency-key","in":"header","example":"7f3c9a2e-5b1d-4c8e-9f0a-2d6b8e4c1a37"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"text":{"type":"string","minLength":1,"maxLength":16000}},"required":["type","text"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["media"]},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string","maxLength":2048,"format":"uri"}},"required":["url"],"additionalProperties":false},"minItems":1,"maxItems":10},"caption":{"type":"string","minLength":1,"maxLength":1600}},"required":["type","media"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["template"]},"template":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":512},"language":{"type":"string","minLength":2,"maxLength":35},"variables":{"type":"object","additionalProperties":{"type":"string","maxLength":1024}}},"required":["name"],"additionalProperties":false}},"required":["type","template"],"additionalProperties":false}],"description":"What to send: `{ \"type\": \"text\", \"text\" }`, `{ \"type\": \"media\", \"media\": [{ \"url\" }], \"caption\" }`. Templates (`{ \"type\": \"template\" }`) are not available yet: refused with `422 operation_not_supported`."},"split":{"type":"string","enum":["auto","refuse"],"default":"auto","description":"`auto` (the default) sends a long text as several messages; `refuse` answers `422 content_too_long` instead."},"metadata":{"type":"object","additionalProperties":{},"description":"Your own key/value pairs, up to 4 KB of JSON, repeated in the message's events."}},"required":["content"],"additionalProperties":false},"example":{"content":{"type":"text","text":"Yes, we have a table at 7pm. Shall I book it?"}}}}},"responses":{"202":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"conversationId":{"type":"string","format":"uuid"},"channel":{"type":"string"},"direction":{"type":"string","enum":["inbound","outbound"]},"status":{"type":"string","enum":["queued","sent","delivered","read","failed","received"]},"text":{"type":["string","null"]},"media":{"type":"array","items":{"type":"object","properties":{"url":{"type":"string"},"contentType":{"type":["string","null"]}},"required":["url","contentType"]}},"from":{"type":["string","null"]},"to":{"type":["string","null"]},"bindingId":{"type":["string","null"],"format":"uuid"},"metadata":{"type":"object","additionalProperties":{}},"error":{"type":["object","null"],"properties":{"code":{"type":"string"},"message":{"type":["string","null"]}},"required":["code","message"]},"createdAt":{"type":"string","format":"date-time"},"parts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["queued","sent","delivered","read","failed","received"]}},"required":["id","status"]},"minItems":1}},"required":["id","conversationId","channel","direction","status","text","media","from","to","bindingId","metadata","error","createdAt","parts"]}},"required":["message"]},"example":{"message":{"id":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","direction":"outbound","status":"queued","text":"Yes, we have a table at 7pm. Shall I book it?","media":[],"from":"+14155550100","to":"+15550123","bindingId":null,"metadata":{},"error":null,"createdAt":"2026-10-20T15:04:05.000Z","parts":[{"id":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","status":"queued"}]}}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"402":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"404":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"409":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"413":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"422":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"429":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"502":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}},"description":"Sends a message into an existing conversation. The channel, your sender and the recipient come from the conversation, so you only send the content. This is how your code answers someone who wrote to you.\n\nRequires an API key with the `messages:send` scope."}},"/v1/events":{"get":{"operationId":"listEvents","summary":"List events","description":"Returns events after a cursor, oldest first, with the `cursor` to pass next time. Use it when you cannot receive webhooks or keep a stream open — a cron job, a serverless function. With `waitSec`, an empty page waits for the next event (long polling).\n\nRequires an API key with the `events:read` scope.","tags":["events"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["events:read"],"parameters":[{"schema":{"type":"string","minLength":1},"required":false,"description":"The `cursor` from your previous page. Leave it out to start at the oldest event.","name":"after","in":"query","example":"MDE5MmY1YjEtMGExYi03YzJk"},{"schema":{"type":"string"},"required":false,"description":"Comma-separated event types, or a prefix with `.*`.","name":"types","in":"query","example":"message.*"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"conversationId","in":"query","description":"Only events of this conversation.","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"},{"schema":{"type":"string","minLength":1,"maxLength":64},"required":false,"description":"Only events of this channel's messages.","name":"channel","in":"query","example":"sms"},{"schema":{"type":"integer","minimum":1,"maximum":500},"required":false,"name":"limit","in":"query","description":"How many items to return, 1–500. Default 100.","example":20},{"schema":{"type":"string","enum":["oldest","now"]},"required":false,"description":"Where to start without `after`: `oldest` (the default) or `now`.","name":"from","in":"query","example":"now"},{"schema":{"type":["integer","null"],"minimum":0,"maximum":25},"required":false,"description":"When there is nothing new yet, wait up to this many seconds (1–25) for the first event.","name":"waitSec","in":"query","example":20}],"responses":{"200":{"description":"Committed public events after the cursor, oldest first","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["message.received","message.sent","message.delivered","message.failed","conversation.created","conversation.controller_changed"]},"createdAt":{"type":"string","format":"date-time"},"livemode":{"type":"boolean","default":true},"data":{"type":"object","additionalProperties":{}}},"required":["id","type","createdAt","data"]}},"cursor":{"type":"string"},"hasMore":{"type":"boolean"}},"required":["events","cursor","hasMore"]},"example":{"events":[{"id":"0192f5b1-0a1b-7c2d-8e3f-4a5b6c7d8e90","type":"message.received","createdAt":"2026-10-20T15:04:05.000Z","livemode":false,"data":{"messageId":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","direction":"inbound","bindingId":null,"status":"received","text":"Do you have a table for two tonight?","author":null,"error":null,"metadata":{},"occurredAt":"2026-10-20T15:04:05.000Z"}}],"cursor":"MDE5MmY1YjEtMGExYi03YzJk","hasMore":false}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}}}}},"/v1/events/stream":{"get":{"operationId":"streamEvents","summary":"Stream events","description":"Opens a Server-Sent Events stream: it replays the events after your cursor, then sends new ones as they happen. Each frame carries its cursor as `id:`; reconnect with the last one in `Last-Event-ID` and nothing is missed or repeated. A heartbeat comment arrives every 15 seconds.\n\nThe stream replays up to 7 days; an older cursor is refused with `410 cursor_expired` (page through `GET /v1/events` from it instead).\n\nRequires an API key with the `events:read` scope.","tags":["events"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["events:read"],"parameters":[{"schema":{"type":"string","minLength":1},"required":false,"description":"Resume after this cursor. Leave it out to start live, from now.","name":"after","in":"query","example":"MDE5MmY1YjEtMGExYi03YzJk"},{"schema":{"type":"string"},"required":false,"description":"Comma-separated event types, or a prefix with `.*`.","name":"types","in":"query","example":"message.*"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"conversationId","in":"query","description":"Only events of this conversation.","example":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21"},{"schema":{"type":"string","minLength":1,"maxLength":64},"required":false,"description":"Only events of this channel's messages.","name":"channel","in":"query","example":"sms"},{"schema":{"type":"string"},"required":false,"description":"The last cursor you processed. Takes precedence over `after`; SSE clients send it for you on reconnect.","name":"last-event-id","in":"header","example":"MDE5MmY1YjEtMGExYi03YzJk"}],"responses":{"200":{"description":"An event stream; each `data` is a PublicEventEnvelope","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/PublicEventEnvelope"},"example":{"id":"0192f5b1-0a1b-7c2d-8e3f-4a5b6c7d8e90","type":"message.received","createdAt":"2026-10-20T15:04:05.000Z","livemode":false,"data":{"messageId":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","channel":"sms","direction":"inbound","bindingId":null,"status":"received","text":"Do you have a table for two tonight?","author":null,"error":null,"metadata":{},"occurredAt":"2026-10-20T15:04:05.000Z"}}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"410":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_request","invalid_event_types","invalid_conversation_id","invalid_cursor","cursor_expired","insufficient_scope","no_project","events_unavailable"]},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{}}},"required":["error"]}}}}}}},"/v1/webhooks/subscriptions":{"get":{"operationId":"listWebhookSubscriptions","summary":"List webhook subscriptions","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"responses":{"200":{"description":"Subscriptions this caller can see","content":{"application/json":{"schema":{"type":"object","properties":{"subscriptions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"projectId":{"type":"string"},"url":{"type":"string"},"eventTypes":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"createdByKeyId":{"type":["string","null"]},"restrictTags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","projectId","url","eventTypes","description","enabled","createdByKeyId","restrictTags","createdAt","updatedAt"]}}},"required":["subscriptions"]},"example":{"subscriptions":[{"id":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23","projectId":"0192f5a1-5e6f-7a7b-8c8d-9e0f1a2b3c45","url":"https://example.com/voicelayer/webhooks","eventTypes":["message.*","conversation.*"],"description":"Production receiver","enabled":true,"createdByKeyId":"key_7f2a91","restrictTags":[],"createdAt":"2026-10-20T15:04:05.000Z","updatedAt":"2026-10-20T15:04:05.000Z"}]}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Returns every webhook subscription in your workspace. Signing secrets are never returned after creation; if you lose one, create a new subscription.\n\nRequires an API key with the `webhooks:manage` scope."},"post":{"operationId":"createWebhookSubscription","summary":"Create a webhook subscription","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Your public HTTPS endpoint."},"eventTypes":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":100,"default":[],"description":"Exact event types or a prefix with `.*` (`message.*`). Leave it empty to receive every type."},"description":{"type":"string","maxLength":500,"description":"A label for you, up to 500 characters."}},"required":["url"]},"example":{"url":"https://example.com/voicelayer/webhooks","eventTypes":["message.*","conversation.*"],"description":"Production receiver"}}}},"responses":{"201":{"description":"Created; the signing secret is returned this once","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","properties":{"id":{"type":"string"},"projectId":{"type":"string"},"url":{"type":"string"},"eventTypes":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"createdByKeyId":{"type":["string","null"]},"restrictTags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"secret":{"type":"string"}},"required":["id","projectId","url","eventTypes","description","enabled","createdByKeyId","restrictTags","createdAt","updatedAt","secret"]}},"required":["subscription"]},"example":{"subscription":{"id":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23","projectId":"0192f5a1-5e6f-7a7b-8c8d-9e0f1a2b3c45","url":"https://example.com/voicelayer/webhooks","eventTypes":["message.*","conversation.*"],"description":"Production receiver","enabled":true,"createdByKeyId":"key_7f2a91","restrictTags":[],"createdAt":"2026-10-20T15:04:05.000Z","updatedAt":"2026-10-20T15:04:05.000Z","secret":"<shown only in this response>"}}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Registers an HTTPS endpoint to receive events. The response includes the signing `secret` — the only time you see it. Store it and use it to verify each delivery's `x-voicelayer-signature` header.\n\nRequires an API key with the `webhooks:manage` scope."}},"/v1/webhooks/subscriptions/{id}":{"get":{"operationId":"getWebhookSubscription","summary":"Retrieve a webhook subscription","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The subscription id.","name":"id","in":"path","example":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23"}],"responses":{"200":{"description":"The subscription","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","properties":{"id":{"type":"string"},"projectId":{"type":"string"},"url":{"type":"string"},"eventTypes":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"createdByKeyId":{"type":["string","null"]},"restrictTags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","projectId","url","eventTypes","description","enabled","createdByKeyId","restrictTags","createdAt","updatedAt"]}},"required":["subscription"]},"example":{"subscription":{"id":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23","projectId":"0192f5a1-5e6f-7a7b-8c8d-9e0f1a2b3c45","url":"https://example.com/voicelayer/webhooks","eventTypes":["message.*","conversation.*"],"description":"Production receiver","enabled":true,"createdByKeyId":"key_7f2a91","restrictTags":[],"createdAt":"2026-10-20T15:04:05.000Z","updatedAt":"2026-10-20T15:04:05.000Z"}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"404":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Returns one webhook subscription: its URL, event types and whether it is enabled. The signing secret is not included.\n\nRequires an API key with the `webhooks:manage` scope."},"patch":{"operationId":"updateWebhookSubscription","summary":"Update a webhook subscription","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The subscription id.","name":"id","in":"path","example":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"A new HTTPS endpoint."},"eventTypes":{"type":"array","items":{"type":"string","maxLength":100},"maxItems":100,"description":"The new list of event types (replaces the old one)."},"description":{"type":["string","null"],"maxLength":500,"description":"A new label, or `null` to clear it."},"enabled":{"type":"boolean","description":"`false` pauses deliveries; `true` resumes them."}}},"example":{"enabled":false}}}},"responses":{"200":{"description":"The subscription after the change","content":{"application/json":{"schema":{"type":"object","properties":{"subscription":{"type":"object","properties":{"id":{"type":"string"},"projectId":{"type":"string"},"url":{"type":"string"},"eventTypes":{"type":"array","items":{"type":"string"}},"description":{"type":["string","null"]},"enabled":{"type":"boolean"},"createdByKeyId":{"type":["string","null"]},"restrictTags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string"},"updatedAt":{"type":"string"}},"required":["id","projectId","url","eventTypes","description","enabled","createdByKeyId","restrictTags","createdAt","updatedAt"]}},"required":["subscription"]},"example":{"subscription":{"id":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23","projectId":"0192f5a1-5e6f-7a7b-8c8d-9e0f1a2b3c45","url":"https://example.com/voicelayer/webhooks","eventTypes":["message.*","conversation.*"],"description":"Production receiver","enabled":false,"createdByKeyId":"key_7f2a91","restrictTags":[],"createdAt":"2026-10-20T15:04:05.000Z","updatedAt":"2026-10-20T15:04:05.000Z"}}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"404":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Changes the URL, the event types or the description, or pauses deliveries with `enabled: false`. Fields you leave out stay as they are.\n\nRequires an API key with the `webhooks:manage` scope."},"delete":{"operationId":"deleteWebhookSubscription","summary":"Delete a webhook subscription","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The subscription id.","name":"id","in":"path","example":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23"}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"404":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Removes a webhook subscription permanently. Deliveries already queued for it stop. To pause it instead, update it with `enabled: false`.\n\nRequires an API key with the `webhooks:manage` scope."}},"/v1/webhooks/deliveries":{"get":{"operationId":"listWebhookDeliveries","summary":"List webhook deliveries","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"parameters":[{"schema":{"type":"string"},"required":false,"name":"subscriptionId","in":"query","description":"Only deliveries to this subscription.","example":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23"},{"schema":{"type":"string","maxLength":100},"required":false,"name":"type","in":"query","description":"Only deliveries of this event type.","example":"message.received"},{"schema":{"type":"string","enum":["pending","in_flight","delivered","failed"]},"required":false,"name":"status","in":"query","description":"`pending`, `in_flight`, `delivered` or `failed`.","example":"failed"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"since","in":"query","description":"Only deliveries created at or after this time (ISO 8601).","example":"2026-10-20T00:00:00.000Z"},{"schema":{"type":"string","format":"date-time"},"required":false,"name":"until","in":"query","description":"Only deliveries created before this time (ISO 8601).","example":"2026-10-21T00:00:00.000Z"},{"schema":{"type":"string"},"required":false,"description":"How many items to return, 1–200. Default 50.","name":"limit","in":"query","example":20}],"responses":{"200":{"description":"Deliveries with their attempts, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"deliveries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"subscriptionId":{"type":"string"},"projectId":{"type":"string"},"eventType":{"type":"string"},"eventId":{"type":"string"},"payload":{"type":"object","additionalProperties":{}},"status":{"type":"string","enum":["pending","in_flight","delivered","failed"]},"attempts":{"type":"integer"},"maxAttempts":{"type":"integer"},"lastStatusCode":{"type":["integer","null"]},"lastError":{"type":["string","null"]},"nextAttemptAt":{"type":"string"},"deliveredAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"attemptLog":{"type":"array","items":{"type":"object","properties":{"attempt":{"type":"integer"},"at":{"type":"string"},"statusCode":{"type":["integer","null"]},"errorCode":{"type":["string","null"]},"latencyMs":{"type":"number"}},"required":["attempt","at","statusCode","errorCode","latencyMs"]}}},"required":["id","subscriptionId","projectId","eventType","eventId","payload","status","attempts","maxAttempts","lastStatusCode","lastError","nextAttemptAt","deliveredAt","createdAt","updatedAt"]}}},"required":["deliveries"]},"example":{"deliveries":[{"id":"0192f5b3-4d5e-7f6a-9b7c-8d9e0f1a2b34","subscriptionId":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23","projectId":"0192f5a1-5e6f-7a7b-8c8d-9e0f1a2b3c45","eventType":"message.received","eventId":"0192f5b1-0a1b-7c2d-8e3f-4a5b6c7d8e90","payload":{"id":"0192f5b1-0a1b-7c2d-8e3f-4a5b6c7d8e90","type":"message.received","createdAt":"2026-10-20T15:04:05.000Z","data":{}},"status":"delivered","attempts":1,"maxAttempts":5,"lastStatusCode":200,"lastError":null,"nextAttemptAt":"2026-10-20T15:04:05.000Z","deliveredAt":"2026-10-20T15:04:05.000Z","createdAt":"2026-10-20T15:04:05.000Z","updatedAt":"2026-10-20T15:04:05.000Z","attemptLog":[{"attempt":1,"at":"2026-10-20T15:04:05.000Z","statusCode":200,"errorCode":null,"latencyMs":182}]}]}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Returns recent deliveries, newest first, with each attempt's status code and latency (never your response body). Use it to debug a receiver: a failed delivery is retried up to 5 times, then marked `failed`.\n\nRequires an API key with the `webhooks:manage` scope."}},"/v1/webhooks/deliveries/{id}/redeliver":{"post":{"operationId":"redeliverWebhook","summary":"Retry a webhook delivery","tags":["webhooks"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["webhooks:manage"],"parameters":[{"schema":{"type":"string"},"required":true,"description":"The delivery id.","name":"id","in":"path","example":"0192f5b3-4d5e-7f6a-9b7c-8d9e0f1a2b34"}],"responses":{"200":{"description":"Queued again","content":{"application/json":{"schema":{"type":"object","properties":{"delivery":{"type":"object","properties":{"id":{"type":"string"},"subscriptionId":{"type":"string"},"projectId":{"type":"string"},"eventType":{"type":"string"},"eventId":{"type":"string"},"payload":{"type":"object","additionalProperties":{}},"status":{"type":"string","enum":["pending","in_flight","delivered","failed"]},"attempts":{"type":"integer"},"maxAttempts":{"type":"integer"},"lastStatusCode":{"type":["integer","null"]},"lastError":{"type":["string","null"]},"nextAttemptAt":{"type":"string"},"deliveredAt":{"type":["string","null"]},"createdAt":{"type":"string"},"updatedAt":{"type":"string"},"attemptLog":{"type":"array","items":{"type":"object","properties":{"attempt":{"type":"integer"},"at":{"type":"string"},"statusCode":{"type":["integer","null"]},"errorCode":{"type":["string","null"]},"latencyMs":{"type":"number"}},"required":["attempt","at","statusCode","errorCode","latencyMs"]}}},"required":["id","subscriptionId","projectId","eventType","eventId","payload","status","attempts","maxAttempts","lastStatusCode","lastError","nextAttemptAt","deliveredAt","createdAt","updatedAt"]}},"required":["delivery"]},"example":{"delivery":{"id":"0192f5b3-4d5e-7f6a-9b7c-8d9e0f1a2b34","subscriptionId":"0192f5a7-3c4d-7e5f-8a6b-7c8d9e0f1a23","projectId":"0192f5a1-5e6f-7a7b-8c8d-9e0f1a2b3c45","eventType":"message.received","eventId":"0192f5b1-0a1b-7c2d-8e3f-4a5b6c7d8e90","payload":{"id":"0192f5b1-0a1b-7c2d-8e3f-4a5b6c7d8e90","type":"message.received","createdAt":"2026-10-20T15:04:05.000Z","data":{}},"status":"pending","attempts":1,"maxAttempts":5,"lastStatusCode":200,"lastError":null,"nextAttemptAt":"2026-10-20T15:04:05.000Z","deliveredAt":null,"createdAt":"2026-10-20T15:04:05.000Z","updatedAt":"2026-10-20T15:04:05.000Z","attemptLog":[{"attempt":1,"at":"2026-10-20T15:04:05.000Z","statusCode":200,"errorCode":null,"latencyMs":182}]}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"404":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Queues a delivery again, for example after you fixed your endpoint. The event keeps its `id`, so your receiver can still deduplicate it.\n\nRequires an API key with the `webhooks:manage` scope."}},"/v1/channels":{"get":{"operationId":"listChannels","summary":"List channels","tags":["channels"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["channels:read"],"responses":{"200":{"description":"Each registered channel this workspace may use: baseline capabilities and, per connected Binding, the effective descriptor and readiness","content":{"application/json":{"schema":{"type":"object","properties":{"channels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":"string"},"addressSpace":{"type":"string"},"plugins":{"type":"array","items":{"type":"string"}},"baseline":{"type":"object","properties":{"operations":{"type":"array","items":{"type":"string"}},"direction":{"type":"object","properties":{"inbound":{"type":"boolean"},"outbound":{"type":"boolean"}},"required":["inbound","outbound"]},"initiation":{"type":"object","properties":{"agentInitiated":{"type":"string"},"userInitiated":{"type":"boolean"},"firstContactRule":{"type":"string"}},"required":["agentInitiated","userInitiated","firstContactRule"]},"windows":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"durationSec":{"type":"number"},"opensOn":{"type":"string"},"outside":{"type":"string"}},"required":["kind","durationSec","opensOn","outside"]}},"templates":{"type":"object","properties":{"required":{"type":"string"},"reviewed":{"type":"boolean"}},"required":["required","reviewed"]},"messageTypes":{"type":"array","items":{"type":"string"}},"limits":{"type":"object","additionalProperties":{}}},"required":["operations","direction","initiation","windows","templates","messageTypes","limits"]},"bindings":{"type":"array","items":{"type":"object","properties":{"bindingId":{"type":"string"},"address":{"type":"string"},"capability":{"type":"string"},"connectionId":{"type":["string","null"]},"pluginId":{"type":["string","null"]},"descriptor":{"type":["object","null"],"properties":{"operations":{"type":"array","items":{"type":"string"}},"direction":{"type":"object","properties":{"inbound":{"type":"boolean"},"outbound":{"type":"boolean"}},"required":["inbound","outbound"]},"initiation":{"type":"object","properties":{"agentInitiated":{"type":"string"},"userInitiated":{"type":"boolean"},"firstContactRule":{"type":"string"}},"required":["agentInitiated","userInitiated","firstContactRule"]},"windows":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"durationSec":{"type":"number"},"opensOn":{"type":"string"},"outside":{"type":"string"}},"required":["kind","durationSec","opensOn","outside"]}},"templates":{"type":"object","properties":{"required":{"type":"string"},"reviewed":{"type":"boolean"}},"required":["required","reviewed"]},"messageTypes":{"type":"array","items":{"type":"string"}},"limits":{"type":"object","additionalProperties":{}}},"required":["operations","direction","initiation","windows","templates","messageTypes","limits"]},"readiness":{"type":"object","properties":{"state":{"type":"string"},"connection":{"type":["string","null"]},"ready":{"type":"boolean"}},"required":["state","connection","ready"]}},"required":["bindingId","address","capability","connectionId","pluginId","descriptor","readiness"]}}},"required":["id","displayName","addressSpace","plugins","baseline","bindings"]}}},"required":["channels"]},"example":{"channels":[{"id":"whatsapp","displayName":"WhatsApp","addressSpace":"app","plugins":["vl/whatsapp"],"baseline":{"operations":["receive.message","send.text","reply.in_window"],"direction":{"inbound":true,"outbound":true},"initiation":{"agentInitiated":"template_only","userInitiated":true,"firstContactRule":"user-initiated, or a reviewed template outside the 24-hour window; opt-in is mandatory"},"windows":[{"kind":"reply","durationSec":86400,"opensOn":"inbound_message","outside":"template_only"}],"templates":{"required":"outside_window","reviewed":true},"messageTypes":["text","image"],"limits":{"textChars":4096}},"bindings":[{"bindingId":"0192f5a9-2b3c-7d4e-9f5a-6b7c8d9e0f12","address":"+14155550100","capability":"whatsapp.message","connectionId":"0192f5a3-7a8b-7c9d-8e0f-2a3b4c5d6e67","pluginId":"vl/whatsapp","descriptor":{"operations":["receive.message","send.text","reply.in_window"],"direction":{"inbound":true,"outbound":true},"initiation":{"agentInitiated":"template_only","userInitiated":true,"firstContactRule":"user-initiated, or a reviewed template outside the 24-hour window; opt-in is mandatory"},"windows":[{"kind":"reply","durationSec":86400,"opensOn":"inbound_message","outside":"template_only"}],"templates":{"required":"outside_window","reviewed":true},"messageTypes":["text","image"],"limits":{"textChars":4096}},"readiness":{"state":"ready","connection":"connected","ready":true}}]}]}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Returns the channels your workspace can use and, for each connected sender, whether it is ready. Each channel describes what it can do: who may start a conversation, reply windows (WhatsApp's 24 hours), whether templates are required, and length limits. Read it before sending on a channel for the first time.\n\nRequires an API key with the `channels:read` scope."}},"/v1/channels/whatsapp/templates":{"get":{"operationId":"listWhatsAppTemplates","summary":"List WhatsApp templates","tags":["channels"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["channels:read"],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"bindingId","in":"query","description":"The WhatsApp sender to read templates for (from `GET /v1/channels`).","example":"0192f5a9-2b3c-7d4e-9f5a-6b7c8d9e0f12"}],"responses":{"200":{"description":"The sender's approved templates (read only; sending templates is not available yet)","content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"language":{"type":"string"},"category":{"type":"string"},"status":{"type":"string"},"variables":{"type":"array","items":{"type":"string"}}},"required":["name","language","category","status","variables"]}}},"required":["templates"]},"example":{"templates":[{"name":"order_ready","language":"en_US","category":"UTILITY","status":"APPROVED","variables":["1"]}]}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"404":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Returns the message templates Meta has approved for one of your WhatsApp senders, with their variables. Read only: sending templates is not available yet, so outside WhatsApp's 24-hour window you cannot message a person until they write to you again.\n\nRequires an API key with the `channels:read` scope."}},"/v1/test/inbound":{"post":{"operationId":"createTestInbound","summary":"Simulate an incoming message","description":"Pretends a person wrote to your workspace from a reserved test address, so you can build and test replies without a real phone. Works only with a test key (`vl_test_…`). The conversation is marked `test: true`: every reply in it — yours and your agent's — is delivered to a simulated carrier, never a real one, and costs nothing.\n\nTest addresses: `+15550100` to `+15550199` for SMS and WhatsApp, `test-1`, `test-2`, … for Telegram and Discord, any address at `test.vlayers.ai` for email.\n\nYou don't need a phone number: when your workspace has no sender on the channel, the message arrives on its free test sender, made on first use. The test sender has no agent, so its conversations start with the controller `api` (your code answers).\n\nRequires an API key with the `messages:send` scope.","tags":["test"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["messages:send"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channel":{"type":"string","minLength":1,"maxLength":64,"description":"The channel the message arrives on: `sms`, `whatsapp`, `telegram`, `discord` or `email`."},"from":{"type":"string","minLength":1,"maxLength":320,"description":"A reserved test address: `+15550100` to `+15550199`, `test-<n>`, or an address at `test.vlayers.ai`."},"to":{"type":"string","minLength":1,"maxLength":320,"description":"Which of your senders receives it (a phone number, account address or mailbox). Leave it out to use your one sender on the channel, or your free test sender when you have none."},"text":{"type":"string","minLength":1,"maxLength":4096,"description":"What the person writes, up to 4,096 characters."}},"required":["channel","from","text"],"additionalProperties":false},"example":{"channel":"sms","from":"+15550123","text":"Do you have a table for two tonight?"}}}},"responses":{"202":{"description":"The simulated message was received","content":{"application/json":{"schema":{"type":"object","properties":{"conversationId":{"type":"string","format":"uuid"},"messageId":{"type":["string","null"],"format":"uuid"},"test":{"type":"boolean","description":"Always true: the conversation is stamped test."}},"required":["conversationId","messageId","test"]},"example":{"conversationId":"0192f5b0-7c3e-7a51-9b2d-4e8f1a6c3d21","messageId":"0192f5b0-8d1f-7b62-8c3e-5f9a2b7d4e32","test":true}}}},"400":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"401":{"description":"Unauthorized: no API key, or not a valid one","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Forbidden: a messaging refusal (insufficient_scope, no_project, sms_refused) or the role check (`forbidden`)","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MessagingError"},{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}]}}}},"404":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"409":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"422":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"429":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}},"503":{"description":"Refused: the body names one of the messaging error codes, each documented at its `docs` link","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessagingError"}}}}}}},"/v1/request-logs":{"get":{"operationId":"listRequestLogs","summary":"List API request logs","tags":["logs"],"security":[{"apiKey":[]}],"x-voicelayer-scopes":["logs:read"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"description":"The previous page's `nextCursor`: older requests.","name":"after","in":"query","example":"eyJ0IjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ"},{"schema":{"type":"string","minLength":1,"maxLength":256},"required":false,"description":"A page's `latestCursor`: only newer requests, oldest first. Use it to tail the log.","name":"since","in":"query","example":"eyJ0IjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ"},{"schema":{"type":"string","enum":["all","error","ok"]},"required":false,"description":"`error` for status 400 and above, `ok` for the rest.","name":"status","in":"query","example":"error"},{"schema":{"type":"string","minLength":1,"maxLength":128},"required":false,"name":"apiKeyId","in":"query","description":"Only requests made with this key.","example":"key_7f2a91"},{"schema":{"type":"integer","minimum":1,"maximum":200},"required":false,"name":"limit","in":"query","description":"How many items to return, 1–200. Default 50.","example":20}],"responses":{"200":{"description":"Request logs, newest first (no bodies; 14-day retention)","content":{"application/json":{"schema":{"type":"object","properties":{"logs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"method":{"type":"string"},"route":{"type":"string"},"status":{"type":"integer"},"errorCode":{"type":["string","null"]},"apiKeyId":{"type":["string","null"]},"latencyMs":{"type":"integer"},"requestId":{"type":"string"},"idempotencyKey":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","method","route","status","errorCode","apiKeyId","latencyMs","requestId","idempotencyKey","createdAt"]}},"nextCursor":{"type":["string","null"]},"latestCursor":{"type":["string","null"]}},"required":["logs","nextCursor","latestCursor"]},"example":{"logs":[{"id":"0192f5b2-1b2c-7d3e-8f4a-5b6c7d8e9f01","method":"POST","route":"/v1/messages","status":202,"errorCode":null,"apiKeyId":"key_7f2a91","latencyMs":148,"requestId":"req-8f2c1d","idempotencyKey":"7f3c9a2e-5b1d-4c8e-9f0a-2d6b8e4c1a37","createdAt":"2026-10-20T15:04:05.000Z"}],"nextCursor":null,"latestCursor":"eyJ0IjoiMjAyNi0xMC0yMFQxNTowNDowNVoifQ"}}}},"400":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"401":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"403":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}},"503":{"description":"Refused","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}},"required":["error"],"additionalProperties":{}}}}}},"description":"Returns the API requests made with your workspace's keys, newest first: method, route, status, error code, latency and request id (never bodies). Kept 14 days. Use it to find out why a request failed, by its `requestId`.\n\nRequires an API key with the `logs:read` scope."}}},"webhooks":{}}