{
"error": {
"type": "invalid_request",
"message": "limit must be between 1 and 100.",
"hint": "Pass limit between 1 and 100 (default 20), and page with after or before.",
"doc_url": "https://api.flow.engineer/docs/errors/invalid_request",
"param": "limit"
}
}
{
"error": {
"type": "authentication",
"message": "No valid API key was given.",
"hint": "Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v0/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}
{
"error": {
"type": "outside_window",
"message": "Last message from the contact was 31h ago; WhatsApp allows only templates now.",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"channel": "whatsapp",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
}
}
{
"error": {
"type": "invalid_request",
"message": "The request body is larger than 33554432 bytes.",
"hint": "Send a smaller body; upload media with POST /v0/files and send its file_id instead of inlining it.",
"doc_url": "https://api.flow.engineer/docs/errors/invalid_request"
}
}
{
"error": {
"type": "unsupported_content",
"channel": "telegram",
"param": "kind",
"message": "Carousels work on WhatsApp only.",
"hint": "On Telegram, send a basic message, then one buttons message with an image header per card.",
"doc_url": "https://api.flow.engineer/docs/errors/unsupported_content",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
}
}
{
"error": {
"type": "new_contact_limit",
"message": "This sender has started its 15 new conversations for today.",
"hint": "Retry after 3600 seconds; replies into existing conversations still go.",
"doc_url": "https://api.flow.engineer/docs/errors/new_contact_limit",
"retry_after": 3600,
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
}
}
Send a basic message (text, or media with a caption)
Channel
Works
Limits
Telegram
Yes
text 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; media.filename only with file_id (Telegram names a document sent by url itself)
WhatsApp
Yes
text 4096 characters; a caption 1024 (none on audio: text with media.typeaudio is refused, send the text as its own message); files up to 100 MB
iMessage
Yes
text 9999 characters; a caption 1024; files up to 100 MB
SMS (US, pilot)
Yes
text at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see SmsSegments); media only from numbers with MMS (Sender.sms.mms): images, audio and video up to 5 MB, no documents
Sends text, or one image, video, document or audio file with an optional
caption, into an existing conversation. This is the normal way to reply to
a contact, and the one kind every channel takes. The send passes the send
gate (window rules, pacing) and is queued; the answer is the queued
message. Its progress arrives as message.sent, message.delivered,
message.read or message.failed events. Sends to one conversation go out
in the order they were accepted (see “Order and duplicates”).
text is sent exactly as written: Flow never reads it as markdown, never
strips or converts marks, and never warns. WhatsApp’s app shows its own
marks (*bold*, _italic_) as styles by itself. To style text on Telegram
or iMessage, use that channel’s block: telegram.parse_mode (Telegram’s
own HTML or MarkdownV2) or imessage.styles (ranges of the text). On
iMessage, text that looks like markup still shows as written.
A field or block a channel does not take is refused, never ignored: a
telegram block sent to a WhatsApp conversation answers 422 unsupported_content with paramtelegram, reply_to on SMS with
paramreply_to, link_preview: true on SMS with paramlink_preview. A field this endpoint does not know answers 400 invalid_request naming it in param. media to an SMS number without
MMS answers 422 unsupported_content with parammedia and
channel_codeno_mms; a document on SMS with parammedia.type;
a file larger than the channel takes with parammedia.
iMessage lines with the SMS/RCS add-on (Sender.imessage.fallback):
a message to a contact who cannot get iMessage goes by SMS or RCS. The
network is chosen for each message when it is sent, never by your app, and
the message’s network (also data.message.network in its events) says
which one carried it. A message that went by SMS or RCS shows no
imessage.styles, no imessage.subject and no effect, and cannot be
edited or unsent (422 unsupported_content, channel_codenot_on_sms).
There are no scheduled sends: a message goes out as soon as it passes the
gate, so to send later, wait in your own code and send then.
{
"error": {
"type": "invalid_request",
"message": "limit must be between 1 and 100.",
"hint": "Pass limit between 1 and 100 (default 20), and page with after or before.",
"doc_url": "https://api.flow.engineer/docs/errors/invalid_request",
"param": "limit"
}
}
{
"error": {
"type": "authentication",
"message": "No valid API key was given.",
"hint": "Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v0/sandbox/keys",
"doc_url": "https://api.flow.engineer/docs/errors/authentication"
}
}
{
"error": {
"type": "outside_window",
"message": "Last message from the contact was 31h ago; WhatsApp allows only templates now.",
"hint": "Send a template instead: POST /v0/conversations/{conversation_id}/template.",
"doc_url": "https://api.flow.engineer/docs/errors/outside_window",
"channel": "whatsapp",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
}
}
{
"error": {
"type": "invalid_request",
"message": "The request body is larger than 33554432 bytes.",
"hint": "Send a smaller body; upload media with POST /v0/files and send its file_id instead of inlining it.",
"doc_url": "https://api.flow.engineer/docs/errors/invalid_request"
}
}
{
"error": {
"type": "unsupported_content",
"channel": "telegram",
"param": "kind",
"message": "Carousels work on WhatsApp only.",
"hint": "On Telegram, send a basic message, then one buttons message with an image header per card.",
"doc_url": "https://api.flow.engineer/docs/errors/unsupported_content",
"conversation": "conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
}
}
{
"error": {
"type": "new_contact_limit",
"message": "This sender has started its 15 new conversations for today.",
"hint": "Retry after 3600 seconds; replies into existing conversations still go.",
"doc_url": "https://api.flow.engineer/docs/errors/new_contact_limit",
"retry_after": 3600,
"sender": "snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"
}
}
An API key of one app, sent as Authorization: Bearer <key>. Keys start with
fk_test_ (test mode: sandbox senders and test data only) or fk_live_
(live mode). Keep live keys on your server; never ship them in an app or page.
A unique string (up to 255 characters) that makes this request safe to retry.
A repeat with the same key within 24 hours returns the first answer instead of
acting again. See "Idempotency" in the introduction.
The conversation's ID.
A conversation ID, conv_ and a ULID.
Pattern: ^conv_[0-9A-HJKMNP-TV-Z]{26}$
Example:
"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"
Body
application/json
Text, or one media file with an optional caption, in either direction: the
kind every channel takes (POST /v0/conversations/{conversation_id}/basic).
Give text, media, or both (then text is the caption). A field not
listed here is refused with 400 invalid_request naming it in param;
a field or channel block the conversation's channel does not take answers
422 unsupported_content naming it.
Received from a contact: their text and/or one file. Inbound media always
has url (a Flow file URL, GET /v0/files/{file_id}) and file_id, on
every channel (an SMS contact's MMS files included), and mime_type and
size_bytes once Flow kept the file; send a received file again by its
file_id. On SMS Flow always keeps its own copy (the provider's is
deleted): an MMS file it could not fetch or check arrives as
file_blocked instead.
Always basic. Optional on POST /v0/conversations/{conversation_id}/basic; required where no URL names the kind (webhook replies, the stream, starts, a message's content).
The text, sent exactly as written: no markdown, no stripping. At most
4096 UTF-16 code units on Telegram (an emoji such as 😀 counts as 2),
4096 characters on WhatsApp, 9999 on iMessage, and 10 segments on SMS
(see SmsSegments). With media it is the caption, at most 1024 (UTF-16
code units on Telegram). Optional when media is given. Longer text is
refused with 400 invalid_request.
One image, video, document or audio file. When sending, give exactly one of
url (an HTTPS URL Flow fetches; Flow neither stores nor scans it, and on
Telegram a document by URL works for PDF and ZIP files) or file_id (from
POST /v0/files). Each channel takes files up to its own size: Telegram
50 MB, WhatsApp and iMessage 100 MB, SMS (MMS) 5 MB; a larger file answers
422 unsupported_content with parammedia. SMS carries images, audio
and video, never documents (parammedia.type), and only from numbers
with MMS (channel_codeno_mms).
Send this as an inline reply to an earlier message in the same
conversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no
inline replies: there it answers 422 unsupported_content with paramreply_to. Refused with 404 not_found (paramreply_to) when the
target is not a message in this conversation, and with 400 invalid_request (paramreply_to) when the target never reached the
channel (for example, it failed). If the target fails after the send was
accepted, the reply goes out as a normal message.
Whether links in the text show a rich preview. Left out, the channel's
default applies (Telegram, WhatsApp and iMessage show previews).
false sends links as plain text. SMS never shows previews, and no
channel shows one on a media message: false is accepted there, and
true on SMS or with media answers 422 unsupported_content with
paramlink_preview.
Telegram only: how the message looks and notifies on Telegram. On another
channel the block answers 422 unsupported_content with paramtelegram; an unknown key 400 invalid_request.
iMessage only: styles and a subject line. On another channel the block
answers 422 unsupported_content with paramimessage; an unknown key
400 invalid_request. A message that goes by SMS or RCS (see
Message.network) shows neither.
Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.
Show child attributes
Response
The message passed the gate and is queued for the channel.
One message in or out of a conversation, with its kind and content and its
delivery status. What you send is what the contact gets: Flow never
converts a message into another kind.
A message's content: one kind object, in either direction, with kind
(always present here) saying which. It is exactly what was sent or
received, except metadata, which is kept once, at the message's own
metadata, and not repeated here.
iMessage channel only: the network that carried the message. imessage,
or sms or rcs when the line has the SMS/RCS add-on
(Sender.imessage.fallback) and the contact could not get iMessage. The
network is chosen for each message when it is sent, never by your app.
Set on inbound messages, and on your messages once the channel reports it
(in message.sent, message.delivered or message.failed, as
data.message.network); absent before that and on other channels. A
message that went by sms or rcs showed no imessage.styles, no
imessage.subject and no effect, and edits and unsends of it answer 422 unsupported_content with channel_codenot_on_sms.
SMS text messages only: how the text travels as SMS. Carriers bill and
deliver SMS in segments: 160 GSM-7 characters fit one segment (153 each
when split), but a single character outside GSM-7 (an emoji, curly quotes,
most non-Latin letters) makes the whole text UCS-2, 70 characters in one
segment (67 each when split). An SMS send may use at most 10 segments:
1530 GSM-7 characters (fewer when it uses GSM-7's two-unit characters such
as { or €), or 670 when it holds an emoji or other character outside
GSM-7; a longer text is refused with 400 invalid_request. Absent on MMS
and on other channels.
The Flow ID of the message this one replies to. For a sent message, the
message the send named in reply_to. For a received message, the message it
replies to inline (a Telegram or WhatsApp reply; on iMessage, the thread's
root message). Absent when the message is not a reply or the quoted
message is not known to Flow.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Flow","description":"Build for every chat interface with Flow Framework, or connect your agent through the Unified Messaging API.","colors":{"primary":"#0b7a5a","light":"#3cc497","dark":"#0b7a5a"},"api":{"playground":{"display":"interactive"},"examples":{"defaults":"required","languages":["curl","javascript","python","go"]}},"navbar":{"links":[{"href":"https://flow.engineer","label":"Website"},{"href":"https://github.com/flow-engineer/sdk","label":"Messaging SDKs"}],"primary":{"type":"button","label":"GitHub","href":"https://github.com/flow-engineer/flow"}},"footer":{"socials":{"github":"https://github.com/flow-engineer/flow","website":"https://flow.engineer"}},"search":{"prompt":"Search Flow docs"},"seo":{"indexing":"navigable"},"contextual":{"options":["copy","view","chatgpt","claude","cursor","vscode"],"display":"header"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"flow-messaging","hasAudioNarration":false,"actualSubdomain":"flow-messaging","customDomains":["docs.flow.engineer"],"gitSource":{"type":"github","owner":"flow-engineer","repo":"docs","deployBranch":"main","contentDirectory":"docs","isPrivate":true,"mountPath":"","label":"","_id":"6ada57ce640382e777556fe3"},"chroma":{"latestBuiltDeploymentHistoryId":"6adcda2f2673ac6bc7cb84b8","collectionId":"13fc76e6-8ba2-4c4a-a3f9-68b8b26261dc","liveDeploymentHistoryId":"6adcda2f2673ac6bc7cb84b8","schemaVersion":"v3"},"entitlements":{"AI_CHAT":{"status":"DISABLED"},"WEB_MCP":{"status":"DISABLED"},"NARRATION":{"status":"DISABLED"}},"buildId":"6addc044fbe3b121222676b9","clientVersion":"0.0.3965","searchFilterCounts":[{"language":"default","tag":"Messaging API","count":100},{"language":"default","tag":"HTTP API","count":64},{"language":"default","tag":"Framework","count":27},{"language":"default","tag":"Messages","count":14},{"language":"default","tag":"Errors","count":14},{"language":"default","tag":"Ship to","count":13},{"language":"default","tag":"Concepts","count":11},{"language":"default","tag":"Get started","count":10},{"language":"default","tag":"Senders and templates","count":8},{"language":"default","tag":"Webhook endpoints","count":6}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"isAtlas":false,"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"api-reference/messages/send-a-basic-message-text-or-media-with-a-caption","slug":"/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption","pageMetadata":{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/basic","title":"Send a basic message (text, or media with a caption)","description":"| Channel | Works | Limits |\n|---|---|---|\n| Telegram | Yes | `text` 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; `media.filename` only with `file_id` (Telegram names a document sent by `url` itself) |\n| WhatsApp | Yes | `text` 4096 characters; a caption 1024 (none on audio: `text` with `media.type` `audio` is refused, send the text as its own message); files up to 100 MB |\n| iMessage | Yes | `text` 9999 characters; a caption 1024; files up to 100 MB |\n| SMS (US, pilot) | Yes | `text` at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see `SmsSegments`); `media` only from numbers with MMS (`Sender.sms.mms`): images, audio and video up to 5 MB, no documents |\n\nSends text, or one image, video, document or audio file with an optional\ncaption, into an existing conversation. This is the normal way to reply to\na contact, and the one kind every channel takes. The send passes the send\ngate (window rules, pacing) and is queued; the answer is the queued\nmessage. Its progress arrives as `message.sent`, `message.delivered`,\n`message.read` or `message.failed` events. Sends to one conversation go out\nin the order they were accepted (see \"Order and duplicates\").\n\n`text` is sent exactly as written: Flow never reads it as markdown, never\nstrips or converts marks, and never warns. WhatsApp's app shows its own\nmarks (`*bold*`, `_italic_`) as styles by itself. To style text on Telegram\nor iMessage, use that channel's block: `telegram.parse_mode` (Telegram's\nown HTML or MarkdownV2) or `imessage.styles` (ranges of the text). On\niMessage, text that looks like markup still shows as written.\n\nA field or block a channel does not take is refused, never ignored: a\n`telegram` block sent to a WhatsApp conversation answers `422\nunsupported_content` with `param` `telegram`, `reply_to` on SMS with\n`param` `reply_to`, `link_preview: true` on SMS with `param`\n`link_preview`. A field this endpoint does not know answers `400\ninvalid_request` naming it in `param`. `media` to an SMS number without\nMMS answers `422 unsupported_content` with `param` `media` and\n`channel_code` `no_mms`; a `document` on SMS with `param` `media.type`;\na file larger than the channel takes with `param` `media`.\n\n**iMessage lines with the SMS/RCS add-on** (`Sender.imessage.fallback`):\na message to a contact who cannot get iMessage goes by SMS or RCS. The\nnetwork is chosen for each message when it is sent, never by your app, and\nthe message's `network` (also `data.message.network` in its events) says\nwhich one carried it. A message that went by SMS or RCS shows no\n`imessage.styles`, no `imessage.subject` and no effect, and cannot be\nedited or unsent (`422 unsupported_content`, `channel_code`\n`not_on_sms`).\n\nThere are no scheduled sends: a message goes out as soon as it passes the\ngate, so to send later, wait in your own code and send then.\n","href":"/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption"},"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 p: \"p\",\n strong: \"strong\",\n table: \"table\",\n tbody: \"tbody\",\n td: \"td\",\n th: \"th\",\n thead: \"thead\",\n tr: \"tr\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.table, {\n children: [_jsx(_components.thead, {\n children: _jsxs(_components.tr, {\n children: [_jsx(_components.th, {\n children: \"Channel\"\n }), _jsx(_components.th, {\n children: \"Works\"\n }), _jsx(_components.th, {\n children: \"Limits\"\n })]\n })\n }), _jsxs(_components.tbody, {\n children: [_jsxs(_components.tr, {\n children: [_jsx(_components.td, {\n children: \"Telegram\"\n }), _jsx(_components.td, {\n children: \"Yes\"\n }), _jsxs(_components.td, {\n children: [_jsx(_components.code, {\n children: \"text\"\n }), \" 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; \", _jsx(_components.code, {\n children: \"media.filename\"\n }), \" only with \", _jsx(_components.code, {\n children: \"file_id\"\n }), \" (Telegram names a document sent by \", _jsx(_components.code, {\n children: \"url\"\n }), \" itself)\"]\n })]\n }), _jsxs(_components.tr, {\n children: [_jsx(_components.td, {\n children: \"WhatsApp\"\n }), _jsx(_components.td, {\n children: \"Yes\"\n }), _jsxs(_components.td, {\n children: [_jsx(_components.code, {\n children: \"text\"\n }), \" 4096 characters; a caption 1024 (none on audio: \", _jsx(_components.code, {\n children: \"text\"\n }), \" with \", _jsx(_components.code, {\n children: \"media.type\"\n }), \" \", _jsx(_components.code, {\n children: \"audio\"\n }), \" is refused, send the text as its own message); files up to 100 MB\"]\n })]\n }), _jsxs(_components.tr, {\n children: [_jsx(_components.td, {\n children: \"iMessage\"\n }), _jsx(_components.td, {\n children: \"Yes\"\n }), _jsxs(_components.td, {\n children: [_jsx(_components.code, {\n children: \"text\"\n }), \" 9999 characters; a caption 1024; files up to 100 MB\"]\n })]\n }), _jsxs(_components.tr, {\n children: [_jsx(_components.td, {\n children: \"SMS (US, pilot)\"\n }), _jsx(_components.td, {\n children: \"Yes\"\n }), _jsxs(_components.td, {\n children: [_jsx(_components.code, {\n children: \"text\"\n }), \" at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see \", _jsx(_components.code, {\n children: \"SmsSegments\"\n }), \"); \", _jsx(_components.code, {\n children: \"media\"\n }), \" only from numbers with MMS (\", _jsx(_components.code, {\n children: \"Sender.sms.mms\"\n }), \"): images, audio and video up to 5 MB, no documents\"]\n })]\n })]\n })]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Sends text, or one image, video, document or audio file with an optional\\ncaption, into an existing conversation. This is the normal way to reply to\\na contact, and the one kind every channel takes. The send passes the send\\ngate (window rules, pacing) and is queued; the answer is the queued\\nmessage. Its progress arrives as \", _jsx(_components.code, {\n children: \"message.sent\"\n }), \", \", _jsx(_components.code, {\n children: \"message.delivered\"\n }), \",\\n\", _jsx(_components.code, {\n children: \"message.read\"\n }), \" or \", _jsx(_components.code, {\n children: \"message.failed\"\n }), \" events. Sends to one conversation go out\\nin the order they were accepted (see “Order and duplicates”).\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"text\"\n }), \" is sent exactly as written: Flow never reads it as markdown, never\\nstrips or converts marks, and never warns. WhatsApp’s app shows its own\\nmarks (\", _jsx(_components.code, {\n children: \"*bold*\"\n }), \", \", _jsx(_components.code, {\n children: \"_italic_\"\n }), \") as styles by itself. To style text on Telegram\\nor iMessage, use that channel’s block: \", _jsx(_components.code, {\n children: \"telegram.parse_mode\"\n }), \" (Telegram’s\\nown HTML or MarkdownV2) or \", _jsx(_components.code, {\n children: \"imessage.styles\"\n }), \" (ranges of the text). On\\niMessage, text that looks like markup still shows as written.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A field or block a channel does not take is refused, never ignored: a\\n\", _jsx(_components.code, {\n children: \"telegram\"\n }), \" block sent to a WhatsApp conversation answers \", _jsx(_components.code, {\n children: \"422 unsupported_content\"\n }), \" with \", _jsx(_components.code, {\n children: \"param\"\n }), \" \", _jsx(_components.code, {\n children: \"telegram\"\n }), \", \", _jsx(_components.code, {\n children: \"reply_to\"\n }), \" on SMS with\\n\", _jsx(_components.code, {\n children: \"param\"\n }), \" \", _jsx(_components.code, {\n children: \"reply_to\"\n }), \", \", _jsx(_components.code, {\n children: \"link_preview: true\"\n }), \" on SMS with \", _jsx(_components.code, {\n children: \"param\"\n }), \"\\n\", _jsx(_components.code, {\n children: \"link_preview\"\n }), \". A field this endpoint does not know answers \", _jsx(_components.code, {\n children: \"400 invalid_request\"\n }), \" naming it in \", _jsx(_components.code, {\n children: \"param\"\n }), \". \", _jsx(_components.code, {\n children: \"media\"\n }), \" to an SMS number without\\nMMS answers \", _jsx(_components.code, {\n children: \"422 unsupported_content\"\n }), \" with \", _jsx(_components.code, {\n children: \"param\"\n }), \" \", _jsx(_components.code, {\n children: \"media\"\n }), \" and\\n\", _jsx(_components.code, {\n children: \"channel_code\"\n }), \" \", _jsx(_components.code, {\n children: \"no_mms\"\n }), \"; a \", _jsx(_components.code, {\n children: \"document\"\n }), \" on SMS with \", _jsx(_components.code, {\n children: \"param\"\n }), \" \", _jsx(_components.code, {\n children: \"media.type\"\n }), \";\\na file larger than the channel takes with \", _jsx(_components.code, {\n children: \"param\"\n }), \" \", _jsx(_components.code, {\n children: \"media\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"iMessage lines with the SMS/RCS add-on\"\n }), \" (\", _jsx(_components.code, {\n children: \"Sender.imessage.fallback\"\n }), \"):\\na message to a contact who cannot get iMessage goes by SMS or RCS. The\\nnetwork is chosen for each message when it is sent, never by your app, and\\nthe message’s \", _jsx(_components.code, {\n children: \"network\"\n }), \" (also \", _jsx(_components.code, {\n children: \"data.message.network\"\n }), \" in its events) says\\nwhich one carried it. A message that went by SMS or RCS shows no\\n\", _jsx(_components.code, {\n children: \"imessage.styles\"\n }), \", no \", _jsx(_components.code, {\n children: \"imessage.subject\"\n }), \" and no effect, and cannot be\\nedited or unsent (\", _jsx(_components.code, {\n children: \"422 unsupported_content\"\n }), \", \", _jsx(_components.code, {\n children: \"channel_code\"\n }), \"\\n\", _jsx(_components.code, {\n children: \"not_on_sms\"\n }), \").\"]\n }), \"\\n\", _jsx(_components.p, {\n children: \"There are no scheduled sends: a message goes out as soon as it passes the\\ngate, so to send later, wait in your own code and send then.\"\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":{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/basic","title":"Send a basic message (text, or media with a caption)","description":"| Channel | Works | Limits |\n|---|---|---|\n| Telegram | Yes | `text` 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; `media.filename` only with `file_id` (Telegram names a document sent by `url` itself) |\n| WhatsApp | Yes | `text` 4096 characters; a caption 1024 (none on audio: `text` with `media.type` `audio` is refused, send the text as its own message); files up to 100 MB |\n| iMessage | Yes | `text` 9999 characters; a caption 1024; files up to 100 MB |\n| SMS (US, pilot) | Yes | `text` at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see `SmsSegments`); `media` only from numbers with MMS (`Sender.sms.mms`): images, audio and video up to 5 MB, no documents |\n\nSends text, or one image, video, document or audio file with an optional\ncaption, into an existing conversation. This is the normal way to reply to\na contact, and the one kind every channel takes. The send passes the send\ngate (window rules, pacing) and is queued; the answer is the queued\nmessage. Its progress arrives as `message.sent`, `message.delivered`,\n`message.read` or `message.failed` events. Sends to one conversation go out\nin the order they were accepted (see \"Order and duplicates\").\n\n`text` is sent exactly as written: Flow never reads it as markdown, never\nstrips or converts marks, and never warns. WhatsApp's app shows its own\nmarks (`*bold*`, `_italic_`) as styles by itself. To style text on Telegram\nor iMessage, use that channel's block: `telegram.parse_mode` (Telegram's\nown HTML or MarkdownV2) or `imessage.styles` (ranges of the text). On\niMessage, text that looks like markup still shows as written.\n\nA field or block a channel does not take is refused, never ignored: a\n`telegram` block sent to a WhatsApp conversation answers `422\nunsupported_content` with `param` `telegram`, `reply_to` on SMS with\n`param` `reply_to`, `link_preview: true` on SMS with `param`\n`link_preview`. A field this endpoint does not know answers `400\ninvalid_request` naming it in `param`. `media` to an SMS number without\nMMS answers `422 unsupported_content` with `param` `media` and\n`channel_code` `no_mms`; a `document` on SMS with `param` `media.type`;\na file larger than the channel takes with `param` `media`.\n\n**iMessage lines with the SMS/RCS add-on** (`Sender.imessage.fallback`):\na message to a contact who cannot get iMessage goes by SMS or RCS. The\nnetwork is chosen for each message when it is sent, never by your app, and\nthe message's `network` (also `data.message.network` in its events) says\nwhich one carried it. A message that went by SMS or RCS shows no\n`imessage.styles`, no `imessage.subject` and no effect, and cannot be\nedited or unsent (`422 unsupported_content`, `channel_code`\n`not_on_sms`).\n\nThere are no scheduled sends: a message goes out as soon as it passes the\ngate, so to send later, wait in your own code and send then.\n","href":"/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/_mintlify/custom/flow-messaging/8b05b91b2b2979cc/default-host-redirect.js"],"openApiReferenceData":{"operation":{"operationId":"sendBasic","tags":["Messages"],"summary":"Send a basic message (text, or media with a caption)","description":"| Channel | Works | Limits |\n|---|---|---|\n| Telegram | Yes | `text` 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; `media.filename` only with `file_id` (Telegram names a document sent by `url` itself) |\n| WhatsApp | Yes | `text` 4096 characters; a caption 1024 (none on audio: `text` with `media.type` `audio` is refused, send the text as its own message); files up to 100 MB |\n| iMessage | Yes | `text` 9999 characters; a caption 1024; files up to 100 MB |\n| SMS (US, pilot) | Yes | `text` at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see `SmsSegments`); `media` only from numbers with MMS (`Sender.sms.mms`): images, audio and video up to 5 MB, no documents |\n\nSends text, or one image, video, document or audio file with an optional\ncaption, into an existing conversation. This is the normal way to reply to\na contact, and the one kind every channel takes. The send passes the send\ngate (window rules, pacing) and is queued; the answer is the queued\nmessage. Its progress arrives as `message.sent`, `message.delivered`,\n`message.read` or `message.failed` events. Sends to one conversation go out\nin the order they were accepted (see \"Order and duplicates\").\n\n`text` is sent exactly as written: Flow never reads it as markdown, never\nstrips or converts marks, and never warns. WhatsApp's app shows its own\nmarks (`*bold*`, `_italic_`) as styles by itself. To style text on Telegram\nor iMessage, use that channel's block: `telegram.parse_mode` (Telegram's\nown HTML or MarkdownV2) or `imessage.styles` (ranges of the text). On\niMessage, text that looks like markup still shows as written.\n\nA field or block a channel does not take is refused, never ignored: a\n`telegram` block sent to a WhatsApp conversation answers `422\nunsupported_content` with `param` `telegram`, `reply_to` on SMS with\n`param` `reply_to`, `link_preview: true` on SMS with `param`\n`link_preview`. A field this endpoint does not know answers `400\ninvalid_request` naming it in `param`. `media` to an SMS number without\nMMS answers `422 unsupported_content` with `param` `media` and\n`channel_code` `no_mms`; a `document` on SMS with `param` `media.type`;\na file larger than the channel takes with `param` `media`.\n\n**iMessage lines with the SMS/RCS add-on** (`Sender.imessage.fallback`):\na message to a contact who cannot get iMessage goes by SMS or RCS. The\nnetwork is chosen for each message when it is sent, never by your app, and\nthe message's `network` (also `data.message.network` in its events) says\nwhich one carried it. A message that went by SMS or RCS shows no\n`imessage.styles`, no `imessage.subject` and no effect, and cannot be\nedited or unsent (`422 unsupported_content`, `channel_code`\n`not_on_sms`).\n\nThere are no scheduled sends: a message goes out as soon as it passes the\ngate, so to send later, wait in your own code and send then.\n","parameters":["6511698e-147d-40a2-8555-e64095cd4641"],"requestBody":"b1cc0055-e709-4be0-98e6-c46cf03ace50","responses":{"202":"36366778-055d-4f94-a7c9-532b79ce19e6","400":"ebffcd7b-52c0-48d4-9e86-861390882980","401":"5e0c8478-b78e-4091-81e3-4a2470c4b31d","403":"af2e8427-02f7-4c3c-ad21-77d9d12e8565","404":"8955cc7b-9b01-42dd-b8d2-a57a5fa64cfe","409":"1a418441-b0b9-4262-9d4b-6e1616df42d2","413":"5b84dc34-d928-4821-b679-24458d1b60ac","422":"d112f5b0-489c-479e-8c6c-7e9789892f50","429":"36bbb39b-50a4-429c-9eec-ded81ace924e","default":"f1a15763-f5bc-4fd2-9038-c7d18e3c64bd"},"method":"post","type":"path","servers":["90a9657d-20c1-4182-87ad-a4d557fcda08"],"security":["59c5f960-0d19-49e7-944f-bfe75a0ffe7d"],"path":"/v0/conversations/{conversation_id}/basic","baseUrlOptions":["https://api.flow.engineer"],"title":"Send a basic message (text, or media with a caption)","codeSamples":[],"requestExampleLanguages":["bash","javascript","python","go"],"requiredOnlyExamples":true,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"6511698e-147d-40a2-8555-e64095cd4641":{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique string (up to 255 characters) that makes this request safe to retry.\nA repeat with the same key within 24 hours returns the first answer instead of\nacting again. See \"Idempotency\" in the introduction.\n","schema":{"type":"string","minLength":1,"maxLength":255,"isRequired":false,"description":"A unique string (up to 255 characters) that makes this request safe to retry.\nA repeat with the same key within 24 hours returns the first answer instead of\nacting again. See \"Idempotency\" in the introduction.\n","uniqueKey":"","typeLabel":"string"}},"1c643674-add1-4b85-b368-187f1bb4a7e0":{"name":"conversation_id","in":"path","required":true,"description":"The conversation's ID.","schema":{"type":"string","description":"The conversation's ID.\nA conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"isRequired":true,"uniqueKey":"","typeLabel":"string"}},"b8f576fb-e1a3-42ca-b4ba-30427e2a4165":{"name":"Flow-Version","in":"header","required":false,"description":"The API version to use, as a date. Without it, the version pinned to your app when it was created is used.","schema":{"type":"string","format":"date","examples":["2026-11-01"],"isRequired":false,"description":"The API version to use, as a date. Without it, the version pinned to your app when it was created is used.","uniqueKey":"","typeLabel":"string\u003cdate>"}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Text, or one media file with an optional caption, in either direction: the\nkind every channel takes (`POST /v0/conversations/{conversation_id}/basic`).\nGive `text`, `media`, or both (then `text` is the caption). A field not\nlisted here is refused with `400 invalid_request` naming it in `param`;\na field or channel block the conversation's channel does not take answers\n`422 unsupported_content` naming it.\n\nReceived from a contact: their text and/or one file. Inbound media always\nhas `url` (a Flow file URL, `GET /v0/files/{file_id}`) and `file_id`, on\nevery channel (an SMS contact's MMS files included), and `mime_type` and\n`size_bytes` once Flow kept the file; send a received file again by its\n`file_id`. On SMS Flow always keeps its own copy (the provider's is\ndeleted): an MMS file it could not fetch or check arrives as\n`file_blocked` instead.\n","properties":{"kind":{"type":"string","const":"basic","default":"basic","description":"Always `basic`. Optional on `POST /v0/conversations/{conversation_id}/basic`; required where no URL names the kind (webhook replies, the stream, starts, a message's `content`).","uniqueKey":"kind","typeLabel":"string"},"text":{"type":"string","minLength":1,"maxLength":9999,"description":"The text, sent exactly as written: no markdown, no stripping. At most\n4096 UTF-16 code units on Telegram (an emoji such as 😀 counts as 2),\n4096 characters on WhatsApp, 9999 on iMessage, and 10 segments on SMS\n(see `SmsSegments`). With `media` it is the caption, at most 1024 (UTF-16\ncode units on Telegram). Optional when `media` is given. Longer text is\nrefused with `400 invalid_request`.\n","uniqueKey":"text","typeLabel":"string"},"media":{"type":"object","description":"One image, video, document or audio file. When sending, give exactly one of\n`url` (an HTTPS URL Flow fetches; Flow neither stores nor scans it, and on\nTelegram a document by URL works for PDF and ZIP files) or `file_id` (from\n`POST /v0/files`). Each channel takes files up to its own size: Telegram\n50 MB, WhatsApp and iMessage 100 MB, SMS (MMS) 5 MB; a larger file answers\n`422 unsupported_content` with `param` `media`. SMS carries images, audio\nand video, never documents (`param` `media.type`), and only from numbers\nwith MMS (`channel_code` `no_mms`).\n","required":["type"],"properties":{"type":{"type":"string","enum":["image","video","document","audio"],"description":"What kind of file it is.","x-enum-varnames":["MediaImage","MediaVideo","MediaDocument","MediaAudio"],"isRequired":true,"uniqueKey":"media.type","typeLabel":"enum\u003cstring>"},"url":{"type":"string","format":"uri","description":"Where the bytes are. Sending, an HTTPS URL Flow can fetch; inbound, a Flow file URL.","uniqueKey":"media.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"media.file_id","typeLabel":"string"},"filename":{"type":"string","maxLength":255,"description":"The file's name, shown for documents and taken only with `type` `document` (on another type it answers `422 unsupported_content` with `param` `media.filename`). On Telegram it works only with `file_id`: Telegram names a document sent by `url` itself, so `filename` with `url` answers `422 unsupported_content` with `param` `media.filename`.","uniqueKey":"media.filename","typeLabel":"string"}},"uniqueKey":"media","typeLabel":"object"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"reply_to","typeLabel":"string"},"link_preview":{"type":"boolean","description":"Whether links in the text show a rich preview. Left out, the channel's\ndefault applies (Telegram, WhatsApp and iMessage show previews).\n`false` sends links as plain text. SMS never shows previews, and no\nchannel shows one on a media message: `false` is accepted there, and\n`true` on SMS or with `media` answers `422 unsupported_content` with\n`param` `link_preview`.\n","uniqueKey":"link_preview","typeLabel":"boolean"},"telegram":{"type":"object","description":"Telegram only: how the message looks and notifies on Telegram. On another\nchannel the block answers `422 unsupported_content` with `param`\n`telegram`; an unknown key `400 invalid_request`.\n","additionalProperties":false,"properties":{"parse_mode":{"type":"string","description":"How Telegram reads the text: `HTML` or `MarkdownV2`, Telegram's own\nformatting (see Telegram's Bot API, \"Formatting options\"). Without it the\ntext is plain. Text that Telegram cannot parse is refused by Telegram:\nthe message fails (`message.failed`, `channel_error`).\n","enum":["HTML","MarkdownV2"],"x-enum-varnames":["ParseModeHTML","ParseModeMarkdownV2"],"uniqueKey":"telegram.parse_mode","typeLabel":"enum\u003cstring>"},"disable_notification":{"type":"boolean","description":"Deliver silently, with no sound.","uniqueKey":"telegram.disable_notification","typeLabel":"boolean"},"protect_content":{"type":"boolean","description":"Stop the contact forwarding or saving the message.","uniqueKey":"telegram.protect_content","typeLabel":"boolean"},"show_caption_above_media":{"type":"boolean","description":"Media only. Show the caption above the photo or video instead of below it.","uniqueKey":"telegram.show_caption_above_media","typeLabel":"boolean"},"has_spoiler":{"type":"boolean","description":"Media only (photos and videos). Cover it with a spoiler animation until tapped.","uniqueKey":"telegram.has_spoiler","typeLabel":"boolean"}},"uniqueKey":"telegram","typeLabel":"object"},"imessage":{"type":"object","description":"iMessage only: styles and a subject line. On another channel the block\nanswers `422 unsupported_content` with `param` `imessage`; an unknown key\n`400 invalid_request`. A message that goes by SMS or RCS (see\n`Message.network`) shows neither.\n","additionalProperties":false,"properties":{"styles":{"type":"array","description":"Styled ranges of `text` (see `ImessageStyle`). Each range must lie within `text`; one that does not answers `400 invalid_request` naming it (`imessage.styles[0]`).","items":{"type":"object","description":"One styled range of an iMessage text.","required":["start","length","style"],"properties":{"start":{"type":"integer","minimum":0,"description":"Where the range starts, in UTF-16 code units from the start of `text`.","isRequired":true,"uniqueKey":"imessage.styles.items.[INDEX].start","typeLabel":"integer"},"length":{"type":"integer","minimum":1,"description":"How long the range is, in UTF-16 code units.","isRequired":true,"uniqueKey":"imessage.styles.items.[INDEX].length","typeLabel":"integer"},"style":{"type":"string","description":"The style. `big` and `small` set the text's size; `shake`, `nod`, `explode`, `ripple`, `bloom` and `jitter` animate it.","enum":["bold","italic","underline","strikethrough","big","small","shake","nod","explode","ripple","bloom","jitter"],"isRequired":true,"uniqueKey":"imessage.styles.items.[INDEX].style","typeLabel":"enum\u003cstring>"}},"uniqueKey":"imessage.styles.items.[INDEX]","typeLabel":"object"},"uniqueKey":"imessage.styles","typeLabel":"object[]"},"subject":{"type":"string","minLength":1,"maxLength":200,"description":"iMessage's subject line, shown in bold above the text.","uniqueKey":"imessage.subject","typeLabel":"string"}},"uniqueKey":"imessage","typeLabel":"object"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"metadata","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"text":{"title":"text","value":{"text":"Yes, we deliver to 560103. Delivery takes 2 days."}},"photo":{"title":"photo","value":{"text":"Here is the blue one.","media":{"type":"image","url":"https://example.com/shirt-blue.jpg"}}},"telegram_html":{"title":"telegram_html","value":{"text":"\u003cb>Order 1042\u003c/b> is on its way.","telegram":{"parse_mode":"HTML"}}},"imessage_styles":{"title":"imessage_styles","value":{"text":"Order 1042 is on its way.","imessage":{"styles":[{"start":0,"length":10,"style":"bold"}]}}}},"exampleType":"examples"}},"exampleType":"examples"},"responses":{"36366778-055d-4f94-a7c9-532b79ce19e6":{"description":"The message passed the gate and is queued for the channel.","content":{"application/json":{"schema":{"type":"object","description":"One message in or out of a conversation, with its kind and content and its\ndelivery status. What you send is what the contact gets: Flow never\nconverts a message into another kind.\n","required":["id","conversation","direction","status","content","livemode","created_at"],"properties":{"id":{"type":"string","description":"A message ID, `msg_` and a ULID.","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"isRequired":true,"uniqueKey":"id","typeLabel":"string"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"isRequired":true,"uniqueKey":"conversation","typeLabel":"string"},"direction":{"type":"string","description":"`in` from the contact, `out` from your app.","enum":["in","out"],"isRequired":true,"uniqueKey":"direction","typeLabel":"enum\u003cstring>"},"status":{"type":"string","description":"- `received`: inbound from the contact.\n- `queued`: accepted by the gate, waiting for its turn in the conversation.\n- `sent`: the channel accepted it.\n- `delivered`: it reached the contact's device, where the channel reports this.\n- `read`: the contact read it, where the channel reports this.\n- `failed`: it could not be sent; see `error`.\n- `unsent`: you unsent it.\n","enum":["received","queued","sent","delivered","read","failed","unsent"],"isRequired":true,"uniqueKey":"status","typeLabel":"enum\u003cstring>"},"content":{"oneOf":[{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"basic","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"basic","isRequired":true,"uniqueKey":"content.oneOf.0.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","minLength":1,"maxLength":9999,"description":"The text, sent exactly as written: no markdown, no stripping. At most\n4096 UTF-16 code units on Telegram (an emoji such as 😀 counts as 2),\n4096 characters on WhatsApp, 9999 on iMessage, and 10 segments on SMS\n(see `SmsSegments`). With `media` it is the caption, at most 1024 (UTF-16\ncode units on Telegram). Optional when `media` is given. Longer text is\nrefused with `400 invalid_request`.\n","uniqueKey":"content.oneOf.0.text","typeLabel":"string"},"media":{"type":"object","description":"One image, video, document or audio file. When sending, give exactly one of\n`url` (an HTTPS URL Flow fetches; Flow neither stores nor scans it, and on\nTelegram a document by URL works for PDF and ZIP files) or `file_id` (from\n`POST /v0/files`). Each channel takes files up to its own size: Telegram\n50 MB, WhatsApp and iMessage 100 MB, SMS (MMS) 5 MB; a larger file answers\n`422 unsupported_content` with `param` `media`. SMS carries images, audio\nand video, never documents (`param` `media.type`), and only from numbers\nwith MMS (`channel_code` `no_mms`).\n","required":["type"],"properties":{"type":{"type":"string","enum":["image","video","document","audio"],"description":"What kind of file it is.","x-enum-varnames":["MediaImage","MediaVideo","MediaDocument","MediaAudio"],"isRequired":true,"uniqueKey":"content.oneOf.0.media.type","typeLabel":"enum\u003cstring>"},"url":{"type":"string","format":"uri","description":"Where the bytes are. Sending, an HTTPS URL Flow can fetch; inbound, a Flow file URL.","uniqueKey":"content.oneOf.0.media.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"content.oneOf.0.media.file_id","typeLabel":"string"},"filename":{"type":"string","maxLength":255,"description":"The file's name, shown for documents and taken only with `type` `document` (on another type it answers `422 unsupported_content` with `param` `media.filename`). On Telegram it works only with `file_id`: Telegram names a document sent by `url` itself, so `filename` with `url` answers `422 unsupported_content` with `param` `media.filename`.","uniqueKey":"content.oneOf.0.media.filename","typeLabel":"string"},"mime_type":{"type":"string","readOnly":true,"description":"Inbound only. The real type, checked from the file's first bytes.","uniqueKey":"content.oneOf.0.media.mime_type","typeLabel":"string"},"size_bytes":{"type":"integer","readOnly":true,"description":"Inbound only. The file's size.","uniqueKey":"content.oneOf.0.media.size_bytes","typeLabel":"integer"}},"uniqueKey":"content.oneOf.0.media","typeLabel":"object"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.0.reply_to","typeLabel":"string"},"link_preview":{"type":"boolean","description":"Whether links in the text show a rich preview. Left out, the channel's\ndefault applies (Telegram, WhatsApp and iMessage show previews).\n`false` sends links as plain text. SMS never shows previews, and no\nchannel shows one on a media message: `false` is accepted there, and\n`true` on SMS or with `media` answers `422 unsupported_content` with\n`param` `link_preview`.\n","uniqueKey":"content.oneOf.0.link_preview","typeLabel":"boolean"},"telegram":{"type":"object","description":"Telegram only: how the message looks and notifies on Telegram. On another\nchannel the block answers `422 unsupported_content` with `param`\n`telegram`; an unknown key `400 invalid_request`.\n","additionalProperties":false,"properties":{"parse_mode":{"type":"string","description":"How Telegram reads the text: `HTML` or `MarkdownV2`, Telegram's own\nformatting (see Telegram's Bot API, \"Formatting options\"). Without it the\ntext is plain. Text that Telegram cannot parse is refused by Telegram:\nthe message fails (`message.failed`, `channel_error`).\n","enum":["HTML","MarkdownV2"],"x-enum-varnames":["ParseModeHTML","ParseModeMarkdownV2"],"uniqueKey":"content.oneOf.0.telegram.parse_mode","typeLabel":"enum\u003cstring>"},"disable_notification":{"type":"boolean","description":"Deliver silently, with no sound.","uniqueKey":"content.oneOf.0.telegram.disable_notification","typeLabel":"boolean"},"protect_content":{"type":"boolean","description":"Stop the contact forwarding or saving the message.","uniqueKey":"content.oneOf.0.telegram.protect_content","typeLabel":"boolean"},"show_caption_above_media":{"type":"boolean","description":"Media only. Show the caption above the photo or video instead of below it.","uniqueKey":"content.oneOf.0.telegram.show_caption_above_media","typeLabel":"boolean"},"has_spoiler":{"type":"boolean","description":"Media only (photos and videos). Cover it with a spoiler animation until tapped.","uniqueKey":"content.oneOf.0.telegram.has_spoiler","typeLabel":"boolean"}},"uniqueKey":"content.oneOf.0.telegram","typeLabel":"object"},"imessage":{"type":"object","description":"iMessage only: styles and a subject line. On another channel the block\nanswers `422 unsupported_content` with `param` `imessage`; an unknown key\n`400 invalid_request`. A message that goes by SMS or RCS (see\n`Message.network`) shows neither.\n","additionalProperties":false,"properties":{"styles":{"type":"array","description":"Styled ranges of `text` (see `ImessageStyle`). Each range must lie within `text`; one that does not answers `400 invalid_request` naming it (`imessage.styles[0]`).","items":{"type":"object","description":"One styled range of an iMessage text.","required":["start","length","style"],"properties":{"start":{"type":"integer","minimum":0,"description":"Where the range starts, in UTF-16 code units from the start of `text`.","isRequired":true,"uniqueKey":"content.oneOf.0.imessage.styles.items.[INDEX].start","typeLabel":"integer"},"length":{"type":"integer","minimum":1,"description":"How long the range is, in UTF-16 code units.","isRequired":true,"uniqueKey":"content.oneOf.0.imessage.styles.items.[INDEX].length","typeLabel":"integer"},"style":{"type":"string","description":"The style. `big` and `small` set the text's size; `shake`, `nod`, `explode`, `ripple`, `bloom` and `jitter` animate it.","enum":["bold","italic","underline","strikethrough","big","small","shake","nod","explode","ripple","bloom","jitter"],"isRequired":true,"uniqueKey":"content.oneOf.0.imessage.styles.items.[INDEX].style","typeLabel":"enum\u003cstring>"}},"uniqueKey":"content.oneOf.0.imessage.styles.items.[INDEX]","typeLabel":"object"},"uniqueKey":"content.oneOf.0.imessage.styles","typeLabel":"object[]"},"subject":{"type":"string","minLength":1,"maxLength":200,"description":"iMessage's subject line, shown in bold above the text.","uniqueKey":"content.oneOf.0.imessage.subject","typeLabel":"string"}},"uniqueKey":"content.oneOf.0.imessage","typeLabel":"object"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.0.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.0.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.0","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"voice","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"voice","isRequired":true,"uniqueKey":"content.oneOf.1.kind","typeLabel":"enum\u003cstring>"},"url":{"type":"string","format":"uri","description":"Where the audio is. Sending, an HTTPS URL Flow can fetch; inbound, a Flow file URL.","uniqueKey":"content.oneOf.1.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"content.oneOf.1.file_id","typeLabel":"string"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.1.reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.1.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.1.metadata","typeLabel":"object"},"duration_seconds":{"type":"number","readOnly":true,"description":"Inbound only. The voice note's length.","uniqueKey":"content.oneOf.1.duration_seconds","typeLabel":"number"},"transcript":{"type":"string","readOnly":true,"description":"Inbound only, on iMessage, when iMessage made a transcript of the voice note. What was said.","uniqueKey":"content.oneOf.1.transcript","typeLabel":"string"}},"isRequired":true,"uniqueKey":"content.oneOf.1","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","text","buttons"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"buttons","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"buttons","isRequired":true,"uniqueKey":"content.oneOf.2.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","minLength":1,"maxLength":4096,"description":"The text above the buttons, sent exactly as written: at most 4096 UTF-16\ncode units on Telegram, or 1024 when the message has a media `header`\n(Telegram's caption limit), and 1024 characters on WhatsApp (its limit\nfor messages with buttons). Longer text is refused with `400\ninvalid_request`.\n","isRequired":true,"uniqueKey":"content.oneOf.2.text","typeLabel":"string"},"buttons":{"type":"array","minItems":1,"maxItems":10,"description":"The buttons, in order: 1 to 10 on Telegram; on WhatsApp 1 to 3 reply\nbuttons or exactly one URL button (anything else answers `422\nunsupported_content` with `param` `buttons`; send a `list` for more\nchoices).\n","items":{"oneOf":[{"type":"object","description":"A reply button (`id` and `label`) or a link button (`url` and `label`).","required":["id","label"],"properties":{"id":{"type":"string","minLength":1,"maxLength":64,"description":"Your ID for the button, returned in `button_reply` as `button_id`: 1 to 64\nbytes (Telegram's limit for a button's data), so at most 64 ASCII\ncharacters and fewer for other characters. Labels may repeat; the ID is\nwhat tells the taps apart, so buttons that share a label (a \"Details\" on\nevery card) get their own IDs, such as `details:listing-17`.\n","isRequired":true,"uniqueKey":"content.oneOf.2.buttons.items.[INDEX].oneOf.0.id","typeLabel":"string"},"label":{"type":"string","minLength":1,"maxLength":20,"description":"The button's text. WhatsApp shows at most 20 characters.","isRequired":true,"uniqueKey":"content.oneOf.2.buttons.items.[INDEX].oneOf.0.label","typeLabel":"string"}},"uniqueKey":"content.oneOf.2.buttons.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"A reply button (`id` and `label`) or a link button (`url` and `label`).","required":["url","label"],"properties":{"url":{"type":"string","format":"uri","description":"The HTTPS link to open.","isRequired":true,"uniqueKey":"content.oneOf.2.buttons.items.[INDEX].oneOf.1.url","typeLabel":"string\u003curi>"},"label":{"type":"string","minLength":1,"maxLength":20,"description":"The button's text.","isRequired":true,"uniqueKey":"content.oneOf.2.buttons.items.[INDEX].oneOf.1.label","typeLabel":"string"}},"uniqueKey":"content.oneOf.2.buttons.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"content.oneOf.2.buttons.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"content.oneOf.2.buttons","typeLabel":"object[]"},"header":{"type":"object","description":"What is shown above a buttons message's text, or a carousel card's image or\nvideo: an image, a video, a document or a short title. A media header\ntakes exactly one of `url` (an HTTPS URL Flow fetches) or `file_id` (from\n`POST /v0/files`), and is fetched and checked for the channel like a basic\nmessage's `media` (so WebP and other formats work); a `text` header takes\n`text`. Anything else, or a value over a limit, is refused with `400\ninvalid_request` naming the field in `param`.\n\nWhatsApp shows the header at the top of the same message bubble. Telegram\nsends one message: the media with the text as its caption and the buttons\nunder it; a `text` header is the message's first line, in bold.\n","required":["type"],"properties":{"type":{"type":"string","enum":["image","video","document","text"],"description":"What the header holds.","isRequired":true,"uniqueKey":"content.oneOf.2.header.type","typeLabel":"enum\u003cstring>"},"url":{"type":"string","format":"uri","description":"Media headers only. An HTTPS URL of the media, which Flow fetches.","uniqueKey":"content.oneOf.2.header.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"content.oneOf.2.header.file_id","typeLabel":"string"},"text":{"type":"string","minLength":1,"maxLength":60,"description":"`text` headers only. The title, 1 to 60 characters (WhatsApp's header limit).","uniqueKey":"content.oneOf.2.header.text","typeLabel":"string"},"filename":{"type":"string","maxLength":255,"description":"`document` headers only. The file's name, shown with the document.","uniqueKey":"content.oneOf.2.header.filename","typeLabel":"string"}},"examples":[{"type":"image","url":"https://example.com/menu.webp"},{"type":"text","text":"Your order"}],"uniqueKey":"content.oneOf.2.header","typeLabel":"object"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.2.reply_to","typeLabel":"string"},"telegram":{"type":"object","description":"Telegram only: how the message looks and notifies on Telegram. On another\nchannel the block answers `422 unsupported_content` with `param`\n`telegram`; an unknown key `400 invalid_request`.\n","additionalProperties":false,"properties":{"parse_mode":{"type":"string","description":"How Telegram reads the text: `HTML` or `MarkdownV2`, Telegram's own\nformatting (see Telegram's Bot API, \"Formatting options\"). Without it the\ntext is plain. Text that Telegram cannot parse is refused by Telegram:\nthe message fails (`message.failed`, `channel_error`).\n","enum":["HTML","MarkdownV2"],"x-enum-varnames":["ParseModeHTML","ParseModeMarkdownV2"],"uniqueKey":"content.oneOf.2.telegram.parse_mode","typeLabel":"enum\u003cstring>"},"disable_notification":{"type":"boolean","description":"Deliver silently, with no sound.","uniqueKey":"content.oneOf.2.telegram.disable_notification","typeLabel":"boolean"},"protect_content":{"type":"boolean","description":"Stop the contact forwarding or saving the message.","uniqueKey":"content.oneOf.2.telegram.protect_content","typeLabel":"boolean"}},"uniqueKey":"content.oneOf.2.telegram","typeLabel":"object"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.2.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.2.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.2","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","text","button","sections"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"list","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"list","isRequired":true,"uniqueKey":"content.oneOf.3.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","minLength":1,"maxLength":4096,"description":"The message's text, sent exactly as written, 1 to 4096 characters.","isRequired":true,"uniqueKey":"content.oneOf.3.text","typeLabel":"string"},"button":{"type":"string","minLength":1,"maxLength":20,"description":"The label of the button that opens the list, 1 to 20 characters.","isRequired":true,"uniqueKey":"content.oneOf.3.button","typeLabel":"string"},"sections":{"type":"array","minItems":1,"maxItems":10,"description":"1 to 10 sections, in order, with at most 10 rows in all.","items":{"type":"object","description":"One section of a list.","required":["rows"],"properties":{"rows":{"type":"array","minItems":1,"maxItems":10,"description":"The section's rows, in order.","items":{"type":"object","description":"One option of a list.","required":["id","title"],"properties":{"id":{"type":"string","minLength":1,"maxLength":200,"description":"Your ID for the row, returned in `button_reply` as `button_id`. 1 to 200 characters, unique across the list.","isRequired":true,"uniqueKey":"content.oneOf.3.sections.items.[INDEX].rows.items.[INDEX].id","typeLabel":"string"},"title":{"type":"string","minLength":1,"maxLength":24,"description":"The row's title, 1 to 24 characters, returned in `button_reply` as `label`.","isRequired":true,"uniqueKey":"content.oneOf.3.sections.items.[INDEX].rows.items.[INDEX].title","typeLabel":"string"},"description":{"type":"string","minLength":1,"maxLength":72,"description":"A line under the title, at most 72 characters.","uniqueKey":"content.oneOf.3.sections.items.[INDEX].rows.items.[INDEX].description","typeLabel":"string"}},"uniqueKey":"content.oneOf.3.sections.items.[INDEX].rows.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"content.oneOf.3.sections.items.[INDEX].rows","typeLabel":"object[]"},"title":{"type":"string","minLength":1,"maxLength":24,"description":"The section's title, 1 to 24 characters. Required when the list has more than one section.","uniqueKey":"content.oneOf.3.sections.items.[INDEX].title","typeLabel":"string"}},"uniqueKey":"content.oneOf.3.sections.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"content.oneOf.3.sections","typeLabel":"object[]"},"header":{"type":"string","minLength":1,"maxLength":60,"description":"A title shown above the text, 1 to 60 characters.","uniqueKey":"content.oneOf.3.header","typeLabel":"string"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.3.reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.3.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.3.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.3","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","text","cards"],"example":{"text":"Three picks for you","cards":[{"header":{"type":"image","url":"https://example.com/a.jpg"},"text":"Linen shirt, 1,499","buttons":[{"id":"buy_a","label":"Buy"}]},{"header":{"type":"image","url":"https://example.com/b.jpg"},"text":"Denim jacket, 2,999","buttons":[{"id":"buy_b","label":"Buy"}]}]},"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"carousel","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"carousel","isRequired":true,"uniqueKey":"content.oneOf.4.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","minLength":1,"maxLength":1024,"description":"The message text shown above the cards, 1 to 1024 characters. Longer text is refused with `400 invalid_request`.","isRequired":true,"uniqueKey":"content.oneOf.4.text","typeLabel":"string"},"cards":{"type":"array","minItems":2,"maxItems":10,"description":"2 to 10 cards, in the order shown (left to right).","items":{"type":"object","description":"One card of a carousel.","required":["header","buttons"],"properties":{"header":{"type":"object","description":"The card's image or video, a `ContentHeader` of type `image` or `video` only (by `url` or `file_id`); any other type is refused with `400 invalid_request` at `cards[i].header.type`.","required":["type"],"properties":{"type":{"type":"string","enum":["image","video","document","text"],"description":"What the header holds.","isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].header.type","typeLabel":"enum\u003cstring>"},"url":{"type":"string","format":"uri","description":"Media headers only. An HTTPS URL of the media, which Flow fetches.","uniqueKey":"content.oneOf.4.cards.items.[INDEX].header.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"content.oneOf.4.cards.items.[INDEX].header.file_id","typeLabel":"string"},"text":{"type":"string","minLength":1,"maxLength":60,"description":"`text` headers only. The title, 1 to 60 characters (WhatsApp's header limit).","uniqueKey":"content.oneOf.4.cards.items.[INDEX].header.text","typeLabel":"string"},"filename":{"type":"string","maxLength":255,"description":"`document` headers only. The file's name, shown with the document.","uniqueKey":"content.oneOf.4.cards.items.[INDEX].header.filename","typeLabel":"string"}},"examples":[{"type":"image","url":"https://example.com/menu.webp"},{"type":"text","text":"Your order"}],"isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].header","typeLabel":"object"},"buttons":{"type":"array","minItems":1,"maxItems":2,"description":"Exactly one URL button, or 1 to 2 reply buttons; the same number and kind on every card. Labels are at most 20 characters.","items":{"oneOf":[{"type":"object","description":"A reply button (`id` and `label`) or a link button (`url` and `label`).","required":["id","label"],"properties":{"id":{"type":"string","minLength":1,"maxLength":64,"description":"Your ID for the button, returned in `button_reply` as `button_id`: 1 to 64\nbytes (Telegram's limit for a button's data), so at most 64 ASCII\ncharacters and fewer for other characters. Labels may repeat; the ID is\nwhat tells the taps apart, so buttons that share a label (a \"Details\" on\nevery card) get their own IDs, such as `details:listing-17`.\n","isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX].oneOf.0.id","typeLabel":"string"},"label":{"type":"string","minLength":1,"maxLength":20,"description":"The button's text. WhatsApp shows at most 20 characters.","isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX].oneOf.0.label","typeLabel":"string"}},"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX].oneOf.0","typeLabel":"object"},{"type":"object","description":"A reply button (`id` and `label`) or a link button (`url` and `label`).","required":["url","label"],"properties":{"url":{"type":"string","format":"uri","description":"The HTTPS link to open.","isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX].oneOf.1.url","typeLabel":"string\u003curi>"},"label":{"type":"string","minLength":1,"maxLength":20,"description":"The button's text.","isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX].oneOf.1.label","typeLabel":"string"}},"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX].oneOf.1","typeLabel":"object"}],"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"content.oneOf.4.cards.items.[INDEX].buttons","typeLabel":"object[]"},"text":{"type":"string","minLength":1,"maxLength":160,"description":"The card's text, at most 160 characters and 2 line breaks.","uniqueKey":"content.oneOf.4.cards.items.[INDEX].text","typeLabel":"string"}},"uniqueKey":"content.oneOf.4.cards.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"content.oneOf.4.cards","typeLabel":"object[]"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.4.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.4.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.4","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","template_id","language"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"template","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"template","isRequired":true,"uniqueKey":"content.oneOf.5.kind","typeLabel":"enum\u003cstring>"},"template_id":{"type":"string","description":"A template ID, `tpl_` and a ULID.","pattern":"^tpl_[0-9A-HJKMNP-TV-Z]{26}$","examples":["tpl_01JB8Z9X2D4F6H8K0M2P4R6T8V"],"isRequired":true,"uniqueKey":"content.oneOf.5.template_id","typeLabel":"string"},"language":{"type":"string","description":"The template language to use, as Meta names it (`en`, `en_US`, `hi`).","isRequired":true,"uniqueKey":"content.oneOf.5.language","typeLabel":"string"},"params":{"type":"object","description":"Values for the template's placeholders.","properties":{"header":{"type":"object","description":"The value of a template's header, when it has a placeholder or media.","required":["kind"],"properties":{"kind":{"type":"string","enum":["text","image","video","document"],"description":"What the header holds.","isRequired":true,"uniqueKey":"content.oneOf.5.params.header.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","description":"For `text` headers, the placeholder's value.","uniqueKey":"content.oneOf.5.params.header.text","typeLabel":"string"},"url":{"type":"string","format":"uri","description":"For media headers, an HTTPS URL of the media.","uniqueKey":"content.oneOf.5.params.header.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"content.oneOf.5.params.header.file_id","typeLabel":"string"}},"uniqueKey":"content.oneOf.5.params.header","typeLabel":"object"},"body":{"type":"array","description":"Values for the body's `{{1}}`, `{{2}}`, ... in order.","items":{"type":"string","uniqueKey":"content.oneOf.5.params.body.items.[INDEX]","typeLabel":"string"},"uniqueKey":"content.oneOf.5.params.body","typeLabel":"string[]"},"buttons":{"type":"array","description":"Values for buttons that take one (URL suffixes, quick-reply payloads).","items":{"type":"object","description":"The value for one of the template's buttons.","required":["index","value"],"properties":{"index":{"type":"integer","minimum":0,"maximum":9,"description":"The button's position in the template, from 0.","isRequired":true,"uniqueKey":"content.oneOf.5.params.buttons.items.[INDEX].index","typeLabel":"integer"},"value":{"type":"string","description":"The URL suffix or the quick-reply payload.","isRequired":true,"uniqueKey":"content.oneOf.5.params.buttons.items.[INDEX].value","typeLabel":"string"}},"uniqueKey":"content.oneOf.5.params.buttons.items.[INDEX]","typeLabel":"object"},"uniqueKey":"content.oneOf.5.params.buttons","typeLabel":"object[]"},"cards":{"type":"array","maxItems":10,"description":"Carousel templates only. Values for each card's header, body placeholders and buttons.","items":{"type":"object","description":"The values for one card of a carousel template.","required":["card_index"],"properties":{"card_index":{"type":"integer","minimum":0,"maximum":9,"description":"The card's position in the template, from 0.","isRequired":true,"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].card_index","typeLabel":"integer"},"header":{"type":"object","description":"The card's image or video (`kind` `image` or `video`, by `url` or `file_id`).","required":["kind"],"properties":{"kind":{"type":"string","enum":["text","image","video","document"],"description":"What the header holds.","isRequired":true,"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].header.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","description":"For `text` headers, the placeholder's value.","uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].header.text","typeLabel":"string"},"url":{"type":"string","format":"uri","description":"For media headers, an HTTPS URL of the media.","uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].header.url","typeLabel":"string\u003curi>"},"file_id":{"type":"string","description":"A file ID, `file_` and a ULID.","pattern":"^file_[0-9A-HJKMNP-TV-Z]{26}$","examples":["file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5"],"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].header.file_id","typeLabel":"string"}},"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].header","typeLabel":"object"},"body":{"type":"array","description":"Values for the card body's `{{1}}`, `{{2}}`, ... in order.","items":{"type":"string","uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].body.items.[INDEX]","typeLabel":"string"},"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].body","typeLabel":"string[]"},"buttons":{"type":"array","description":"Values for the card's buttons that take one (URL suffixes, quick-reply payloads).","items":{"type":"object","description":"The value for one of the template's buttons.","required":["index","value"],"properties":{"index":{"type":"integer","minimum":0,"maximum":9,"description":"The button's position in the template, from 0.","isRequired":true,"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].buttons.items.[INDEX].index","typeLabel":"integer"},"value":{"type":"string","description":"The URL suffix or the quick-reply payload.","isRequired":true,"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].buttons.items.[INDEX].value","typeLabel":"string"}},"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].buttons.items.[INDEX]","typeLabel":"object"},"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX].buttons","typeLabel":"object[]"}},"examples":[{"card_index":0,"header":{"kind":"image","url":"https://example.com/a.jpg"},"body":["Linen shirt"],"buttons":[{"index":0,"value":"buy_a"}]}],"uniqueKey":"content.oneOf.5.params.cards.items.[INDEX]","typeLabel":"object"},"uniqueKey":"content.oneOf.5.params.cards","typeLabel":"object[]"}},"uniqueKey":"content.oneOf.5.params","typeLabel":"object"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.5.reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.5.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.5.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.5","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","name"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"contact_card","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"contact_card","isRequired":true,"uniqueKey":"content.oneOf.6.kind","typeLabel":"enum\u003cstring>"},"name":{"type":"string","minLength":1,"description":"The person's or business's name.","isRequired":true,"uniqueKey":"content.oneOf.6.name","typeLabel":"string"},"phones":{"type":"array","description":"Phone numbers, E.164 where known. Telegram needs at least one (else `422 unsupported_content`, `param` `phones`).","items":{"type":"string","uniqueKey":"content.oneOf.6.phones.items.[INDEX]","typeLabel":"string"},"uniqueKey":"content.oneOf.6.phones","typeLabel":"string[]"},"emails":{"type":"array","description":"Email addresses.","items":{"type":"string","format":"email","uniqueKey":"content.oneOf.6.emails.items.[INDEX]","typeLabel":"string\u003cemail>"},"uniqueKey":"content.oneOf.6.emails","typeLabel":"string\u003cemail>[]"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.6.reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.6.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.6.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.6","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","lat","lng"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"location","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"location","isRequired":true,"uniqueKey":"content.oneOf.7.kind","typeLabel":"enum\u003cstring>"},"lat":{"type":"number","minimum":-90,"maximum":90,"description":"Latitude in degrees.","isRequired":true,"uniqueKey":"content.oneOf.7.lat","typeLabel":"number"},"lng":{"type":"number","minimum":-180,"maximum":180,"description":"Longitude in degrees.","isRequired":true,"uniqueKey":"content.oneOf.7.lng","typeLabel":"number"},"name":{"type":"string","description":"The place's name.","uniqueKey":"content.oneOf.7.name","typeLabel":"string"},"address":{"type":"string","description":"The place's address.","uniqueKey":"content.oneOf.7.address","typeLabel":"string"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.7.reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.7.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.7.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.7","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","text","effect"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"effect","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"effect","isRequired":true,"uniqueKey":"content.oneOf.8.kind","typeLabel":"enum\u003cstring>"},"text":{"type":"string","minLength":1,"maxLength":9999,"description":"The text, sent exactly as written, at most 9999 characters. Longer text is refused with `400 invalid_request`.","isRequired":true,"uniqueKey":"content.oneOf.8.text","typeLabel":"string"},"effect":{"type":"string","description":"The effect.","enum":["slam","loud","gentle","invisible_ink","echo","spotlight","balloons","confetti","love","lasers","fireworks","celebration"],"isRequired":true,"uniqueKey":"content.oneOf.8.effect","typeLabel":"enum\u003cstring>"},"reply_to":{"type":"string","description":"Send this as an inline reply to an earlier message in the same\nconversation (Telegram, WhatsApp and iMessage show it quoted). SMS has no\ninline replies: there it answers `422 unsupported_content` with `param`\n`reply_to`. Refused with `404 not_found` (`param` `reply_to`) when the\ntarget is not a message in this conversation, and with `400\ninvalid_request` (`param` `reply_to`) when the target never reached the\nchannel (for example, it failed). If the target fails after the send was\naccepted, the reply goes out as a normal message.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.8.reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"content.oneOf.8.metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"content.oneOf.8.metadata","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.8","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","message_id","emoji"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"reaction","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"reaction","isRequired":true,"uniqueKey":"content.oneOf.9.kind","typeLabel":"enum\u003cstring>"},"message_id":{"type":"string","description":"A message ID, `msg_` and a ULID.","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"isRequired":true,"uniqueKey":"content.oneOf.9.message_id","typeLabel":"string"},"emoji":{"oneOf":[{"type":"string","maxLength":16,"description":"One emoji, or `null` to remove the reaction. On Telegram only its reaction emoji (listed on the endpoint); any other answers `422 unsupported_content` with `param` `emoji`.","isRequired":true,"uniqueKey":"content.oneOf.9.emoji.oneOf.0","typeLabel":"string"},{"type":"null","maxLength":16,"description":"One emoji, or `null` to remove the reaction. On Telegram only its reaction emoji (listed on the endpoint); any other answers `422 unsupported_content` with `param` `emoji`.","isRequired":true,"uniqueKey":"content.oneOf.9.emoji.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"content.oneOf.9.emoji","typeLabel":"string | null"},"telegram":{"type":"object","description":"Telegram only. On another channel the block answers `422\nunsupported_content` with `param` `telegram`; an unknown key `400\ninvalid_request`.\n","additionalProperties":false,"properties":{"is_big":{"type":"boolean","description":"Show the reaction with a large animation.","uniqueKey":"content.oneOf.9.telegram.is_big","typeLabel":"boolean"}},"uniqueKey":"content.oneOf.9.telegram","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.9","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"typing","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"typing","isRequired":true,"uniqueKey":"content.oneOf.10.kind","typeLabel":"enum\u003cstring>"},"imessage":{"type":"object","description":"iMessage only. On another channel the block answers `422\nunsupported_content` with `param` `imessage`; an unknown key `400\ninvalid_request`.\n","additionalProperties":false,"properties":{"duration_seconds":{"type":"integer","minimum":1,"maximum":60,"description":"How long to show the indicator, 1 to 60 seconds, unless a message goes first.","uniqueKey":"content.oneOf.10.imessage.duration_seconds","typeLabel":"integer"}},"uniqueKey":"content.oneOf.10.imessage","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.10","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","default":"read","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"read","isRequired":true,"uniqueKey":"content.oneOf.11.kind","typeLabel":"enum\u003cstring>"},"up_to":{"type":"string","description":"WhatsApp only. The latest inbound message to mark read (default the latest inbound message). iMessage marks the whole conversation read, so `up_to` there answers `422 unsupported_content` with `param` `up_to`.","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.11.up_to","typeLabel":"string"}},"isRequired":true,"uniqueKey":"content.oneOf.11","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","message_id","text"],"properties":{"text":{"type":"string","minLength":1,"maxLength":9999,"description":"The new text: at most 4096 UTF-16 code units on Telegram (1024 when it\nreplaces a media message's caption) and 9999 characters on iMessage.\nLonger text is refused with `400 invalid_request`.\n","isRequired":true,"uniqueKey":"content.oneOf.12.text","typeLabel":"string"},"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"edit","isRequired":true,"uniqueKey":"content.oneOf.12.kind","typeLabel":"enum\u003cstring>"},"message_id":{"type":"string","description":"A message ID, `msg_` and a ULID.","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"isRequired":true,"uniqueKey":"content.oneOf.12.message_id","typeLabel":"string"},"telegram":{"type":"object","description":"Telegram only. How Telegram reads the new text. An unknown key is refused with `400 invalid_request`.","additionalProperties":false,"properties":{"parse_mode":{"type":"string","description":"How Telegram reads the text: `HTML` or `MarkdownV2`, Telegram's own\nformatting (see Telegram's Bot API, \"Formatting options\"). Without it the\ntext is plain. Text that Telegram cannot parse is refused by Telegram:\nthe message fails (`message.failed`, `channel_error`).\n","enum":["HTML","MarkdownV2"],"x-enum-varnames":["ParseModeHTML","ParseModeMarkdownV2"],"uniqueKey":"content.oneOf.12.telegram.parse_mode","typeLabel":"enum\u003cstring>"}},"uniqueKey":"content.oneOf.12.telegram","typeLabel":"object"},"imessage":{"type":"object","description":"iMessage only. Styles for the new text. An unknown key is refused with `400 invalid_request`.","additionalProperties":false,"properties":{"styles":{"type":"array","description":"Styled ranges of the new `text` (see `ImessageStyle`).","items":{"type":"object","description":"One styled range of an iMessage text.","required":["start","length","style"],"properties":{"start":{"type":"integer","minimum":0,"description":"Where the range starts, in UTF-16 code units from the start of `text`.","isRequired":true,"uniqueKey":"content.oneOf.12.imessage.styles.items.[INDEX].start","typeLabel":"integer"},"length":{"type":"integer","minimum":1,"description":"How long the range is, in UTF-16 code units.","isRequired":true,"uniqueKey":"content.oneOf.12.imessage.styles.items.[INDEX].length","typeLabel":"integer"},"style":{"type":"string","description":"The style. `big` and `small` set the text's size; `shake`, `nod`, `explode`, `ripple`, `bloom` and `jitter` animate it.","enum":["bold","italic","underline","strikethrough","big","small","shake","nod","explode","ripple","bloom","jitter"],"isRequired":true,"uniqueKey":"content.oneOf.12.imessage.styles.items.[INDEX].style","typeLabel":"enum\u003cstring>"}},"uniqueKey":"content.oneOf.12.imessage.styles.items.[INDEX]","typeLabel":"object"},"uniqueKey":"content.oneOf.12.imessage.styles","typeLabel":"object[]"}},"uniqueKey":"content.oneOf.12.imessage","typeLabel":"object"}},"isRequired":true,"uniqueKey":"content.oneOf.12","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","message_id"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"unsend","isRequired":true,"uniqueKey":"content.oneOf.13.kind","typeLabel":"enum\u003cstring>"},"message_id":{"type":"string","description":"A message ID, `msg_` and a ULID.","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"isRequired":true,"uniqueKey":"content.oneOf.13.message_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"content.oneOf.13","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","button_id","label"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"button_reply","isRequired":true,"uniqueKey":"content.oneOf.14.kind","typeLabel":"enum\u003cstring>"},"button_id":{"type":"string","description":"The `id` of the tapped button or list row.","isRequired":true,"uniqueKey":"content.oneOf.14.button_id","typeLabel":"string"},"label":{"type":"string","description":"The tapped button's label, or the list row's title.","isRequired":true,"uniqueKey":"content.oneOf.14.label","typeLabel":"string"},"message_id":{"type":"string","description":"A message ID, `msg_` and a ULID.","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"uniqueKey":"content.oneOf.14.message_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"content.oneOf.14","typeLabel":"object"},{"type":"object","description":"A message's content: one kind object, in either direction, with `kind`\n(always present here) saying which. It is exactly what was sent or\nreceived, except `metadata`, which is kept once, at the message's own\n`metadata`, and not repeated here.\n","required":["kind","reason"],"properties":{"kind":{"type":"string","description":"The kinds of message. A closed list: a new kind arrives only with a new API\nversion. Each kind has its own schema (`BasicMessage`, `VoiceMessage`, ...)\nand, where it can be sent over HTTP, its own endpoint of the same name\n(`POST /v0/conversations/{conversation_id}/\u003ckind>`, with `contact-card` for\n`contact_card`). `edit` and `unsend` are sent over HTTP with `PATCH` and\n`DELETE /v0/messages/{message_id}`, and are kinds in webhook replies, on\nthe stream and in a message's `content`. `button_reply` and `file_blocked`\nare inbound only.\n\nReceived from a contact: `basic`, `voice`, `button_reply`, `reaction`,\n`location`, `contact_card` and `file_blocked`. Sent: every kind but\n`button_reply` and `file_blocked`.\n","enum":["basic","voice","buttons","list","carousel","template","contact_card","location","effect","reaction","typing","read","edit","unsend","button_reply","file_blocked"],"const":"file_blocked","isRequired":true,"uniqueKey":"content.oneOf.15.kind","typeLabel":"enum\u003cstring>"},"reason":{"type":"string","enum":["malware","type_not_allowed","scan_failed","too_large"],"description":"Why the file was not kept: `malware` (the scan found something), `type_not_allowed`, `scan_failed` (the scanner could not check it; ask the contact to send it again), or `too_large`.","isRequired":true,"uniqueKey":"content.oneOf.15.reason","typeLabel":"enum\u003cstring>"},"media_type":{"type":"string","enum":["image","video","document","audio"],"description":"What kind of file the channel said it was.","uniqueKey":"content.oneOf.15.media_type","typeLabel":"enum\u003cstring>"},"filename":{"type":"string","description":"The file's name, if it had one.","uniqueKey":"content.oneOf.15.filename","typeLabel":"string"},"mime_type":{"type":"string","description":"The real type, read from the file's first bytes, when Flow read them.","uniqueKey":"content.oneOf.15.mime_type","typeLabel":"string"},"size_bytes":{"type":"integer","description":"The file's size, when known.","uniqueKey":"content.oneOf.15.size_bytes","typeLabel":"integer"},"caption":{"type":"string","description":"Text the contact sent with the file.","uniqueKey":"content.oneOf.15.caption","typeLabel":"string"}},"isRequired":true,"uniqueKey":"content.oneOf.15","typeLabel":"object"}],"isRequired":true,"uniqueKey":"content","typeLabel":"object"},"livemode":{"type":"boolean","description":"Whether the message belongs to live mode.","isRequired":true,"uniqueKey":"livemode","typeLabel":"boolean"},"created_at":{"type":"string","format":"date-time","description":"When Flow received (inbound) or accepted (outbound) the message.","isRequired":true,"uniqueKey":"created_at","typeLabel":"string\u003cdate-time>"},"from":{"type":"string","description":"Inbound messages only, on every channel. The contact who wrote it; in a group conversation, which participant. Absent on your own messages.","pattern":"^ct_[0-9A-HJKMNP-TV-Z]{26}$","examples":["ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0"],"readOnly":true,"uniqueKey":"from","typeLabel":"string"},"network":{"type":"string","readOnly":true,"description":"iMessage channel only: the network that carried the message. `imessage`,\nor `sms` or `rcs` when the line has the SMS/RCS add-on\n(`Sender.imessage.fallback`) and the contact could not get iMessage. The\nnetwork is chosen for each message when it is sent, never by your app.\nSet on inbound messages, and on your messages once the channel reports it\n(in `message.sent`, `message.delivered` or `message.failed`, as\n`data.message.network`); absent before that and on other channels. A\nmessage that went by `sms` or `rcs` showed no `imessage.styles`, no\n`imessage.subject` and no effect, and edits and unsends of it answer `422\nunsupported_content` with `channel_code` `not_on_sms`.\n","enum":["imessage","sms","rcs"],"x-enum-varnames":["NetworkImessage","NetworkSms","NetworkRcs"],"uniqueKey":"network","typeLabel":"enum\u003cstring>"},"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"uniqueKey":"error","typeLabel":"object"},"channel_message_id":{"type":"string","description":"The channel's own ID for the message, once the channel accepted it.","uniqueKey":"channel_message_id","typeLabel":"string"},"sms":{"type":"object","readOnly":true,"description":"SMS text messages only: how the text travels as SMS. Carriers bill and\ndeliver SMS in segments: 160 GSM-7 characters fit one segment (153 each\nwhen split), but a single character outside GSM-7 (an emoji, curly quotes,\nmost non-Latin letters) makes the whole text UCS-2, 70 characters in one\nsegment (67 each when split). An SMS send may use at most 10 segments:\n1530 GSM-7 characters (fewer when it uses GSM-7's two-unit characters such\nas `{` or `€`), or 670 when it holds an emoji or other character outside\nGSM-7; a longer text is refused with `400 invalid_request`. Absent on MMS\nand on other channels.\n","required":["segments","encoding"],"properties":{"segments":{"type":"integer","minimum":1,"description":"How many SMS segments the text takes.","isRequired":true,"uniqueKey":"sms.segments","typeLabel":"integer"},"encoding":{"type":"string","description":"`gsm7` or `ucs2`.","enum":["gsm7","ucs2"],"isRequired":true,"uniqueKey":"sms.encoding","typeLabel":"enum\u003cstring>"}},"uniqueKey":"sms","typeLabel":"object"},"reply_to":{"type":"string","description":"The Flow ID of the message this one replies to. For a sent message, the\nmessage the send named in `reply_to`. For a received message, the message it\nreplies to inline (a Telegram or WhatsApp reply; on iMessage, the thread's\nroot message). Absent when the message is not a reply or the quoted\nmessage is not known to Flow.\n","pattern":"^msg_[0-9A-HJKMNP-TV-Z]{26}$","examples":["msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2"],"readOnly":true,"uniqueKey":"reply_to","typeLabel":"string"},"metadata":{"type":"object","description":"Up to 20 string pairs of your own, kept with the object and returned unchanged. Keys up to 40 characters, values up to 500.","maxProperties":20,"additionalProperties":{"type":"string","maxLength":500,"uniqueKey":"metadata.additionalProperties","typeLabel":"string"},"uniqueKey":"metadata","typeLabel":"object"},"updated_at":{"type":"string","format":"date-time","description":"When the status last changed.","uniqueKey":"updated_at","typeLabel":"string\u003cdate-time>"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"id":"msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1","direction":"in","status":"received","content":{"kind":"basic","text":"\u003cstring>","media":{"type":"image","url":"\u003cstring>","file_id":"file_01JB8ZG7Q9S1V3X5Z7B9D1F3G5","filename":"\u003cstring>","mime_type":"\u003cstring>","size_bytes":123},"reply_to":"msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2","link_preview":true,"telegram":{"parse_mode":"HTML","disable_notification":true,"protect_content":true,"show_caption_above_media":true,"has_spoiler":true},"imessage":{"styles":[{"start":1,"length":2,"style":"bold"}],"subject":"\u003cstring>"},"metadata":{}},"livemode":true,"created_at":"2023-11-07T05:31:56Z","from":"ct_01JB8ZB2J4K6N8Q0S2V4W6Y8A0","network":"imessage","error":{"type":"invalid_request","message":"\u003cstring>","hint":"Send a template instead: POST /v0/conversations/{conversation_id}/template.","doc_url":"https://api.flow.engineer/docs/errors/outside_window","param":"\u003cstring>","retry_after":1,"channel":"telegram","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1","sender":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T","channel_code":"\u003cstring>","request_id":"\u003cstring>"},"channel_message_id":"\u003cstring>","sms":{"segments":2,"encoding":"gsm7"},"reply_to":"msg_01JB8ZD4M6P8R0T2V4X6Z8B0C2","metadata":{},"updated_at":"2023-11-07T05:31:56Z"}}},"exampleType":"generated"}},"exampleType":"generated"},"ebffcd7b-52c0-48d4-9e86-861390882980":{"description":"The request is malformed or a parameter is invalid (`invalid_request`).\n`error.param` names the parameter. Every endpoint answers this for a\n`Flow-Version` header that is not a date this API serves (`param`\n`Flow-Version`), and every `POST` that takes an `Idempotency-Key` for a key\nover 255 characters (`param` `Idempotency-Key`).\n","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":{"type":"invalid_request","message":"limit must be between 1 and 100.","hint":"Pass limit between 1 and 100 (default 20), and page with after or before.","doc_url":"https://api.flow.engineer/docs/errors/invalid_request","param":"limit"}},"examples":{"Example":{"title":"Example","value":{"error":{"type":"invalid_request","message":"limit must be between 1 and 100.","hint":"Pass limit between 1 and 100 (default 20), and page with after or before.","doc_url":"https://api.flow.engineer/docs/errors/invalid_request","param":"limit"}}}},"exampleType":"examples"}},"exampleType":"examples"},"5e0c8478-b78e-4091-81e3-4a2470c4b31d":{"description":"The API key is missing, malformed, unknown, revoked or expired (`authentication`).","headers":{"WWW-Authenticate":{"description":"The authentication scheme, `Bearer realm=\"api.flow.engineer\"`. When the\nrequest carried a key that is well formed but unknown, revoked or\nexpired, it also says `error=\"invalid_token\"`:\n`Bearer realm=\"api.flow.engineer\", error=\"invalid_token\"`. A missing or\nmalformed key gets the scheme alone.\n","schema":{"type":"string","examples":["Bearer realm=\"api.flow.engineer\", error=\"invalid_token\""]}}},"content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":{"type":"authentication","message":"No valid API key was given.","hint":"Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v0/sandbox/keys","doc_url":"https://api.flow.engineer/docs/errors/authentication"}},"examples":{"Example":{"title":"Example","value":{"error":{"type":"authentication","message":"No valid API key was given.","hint":"Send the header Authorization: Bearer fk_test_... (or fk_live_...); no key yet? Get a test key with curl -X POST https://api.flow.engineer/v0/sandbox/keys","doc_url":"https://api.flow.engineer/docs/errors/authentication"}}}},"exampleType":"examples"}},"exampleType":"examples"},"af2e8427-02f7-4c3c-ad21-77d9d12e8565":{"description":"The key may not do this, for example a test key using a live sender (`permission`).","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"type":"invalid_request","message":"\u003cstring>","hint":"Send a template instead: POST /v0/conversations/{conversation_id}/template.","doc_url":"https://api.flow.engineer/docs/errors/outside_window","param":"\u003cstring>","retry_after":1,"channel":"telegram","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1","sender":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T","channel_code":"\u003cstring>","request_id":"\u003cstring>"}}}},"exampleType":"generated"}},"exampleType":"generated"},"8955cc7b-9b01-42dd-b8d2-a57a5fa64cfe":{"description":"No such object for this app and mode (`not_found`).","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"type":"invalid_request","message":"\u003cstring>","hint":"Send a template instead: POST /v0/conversations/{conversation_id}/template.","doc_url":"https://api.flow.engineer/docs/errors/outside_window","param":"\u003cstring>","retry_after":1,"channel":"telegram","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1","sender":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T","channel_code":"\u003cstring>","request_id":"\u003cstring>"}}}},"exampleType":"generated"}},"exampleType":"generated"},"1a418441-b0b9-4262-9d4b-6e1616df42d2":{"description":"The request conflicts with the current state: the channel's window is closed\n(`outside_window`: WhatsApp's 24 hours for free-form messages, iMessage's\n5 minutes after the contact's last message for typing), or the idempotency\nkey was used for a different request or is still in use\n(`idempotency_conflict`).\n","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":{"type":"outside_window","message":"Last message from the contact was 31h ago; WhatsApp allows only templates now.","hint":"Send a template instead: POST /v0/conversations/{conversation_id}/template.","doc_url":"https://api.flow.engineer/docs/errors/outside_window","channel":"whatsapp","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"}},"examples":{"Example":{"title":"Example","value":{"error":{"type":"outside_window","message":"Last message from the contact was 31h ago; WhatsApp allows only templates now.","hint":"Send a template instead: POST /v0/conversations/{conversation_id}/template.","doc_url":"https://api.flow.engineer/docs/errors/outside_window","channel":"whatsapp","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"}}}},"exampleType":"examples"}},"exampleType":"examples"},"5b84dc34-d928-4821-b679-24458d1b60ac":{"description":"The request body is larger than Flow takes (`invalid_request`): 32 MB, or\n101 MB for `POST /v0/files` (a 100 MB file and its multipart framing). A body\nthat declares a larger `Content-Length` is refused before it is read. Send\nmedia as a `file_id` from `POST /v0/files` or by `url` instead of inlining it.\n","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":{"type":"invalid_request","message":"The request body is larger than 33554432 bytes.","hint":"Send a smaller body; upload media with POST /v0/files and send its file_id instead of inlining it.","doc_url":"https://api.flow.engineer/docs/errors/invalid_request"}},"examples":{"Example":{"title":"Example","value":{"error":{"type":"invalid_request","message":"The request body is larger than 33554432 bytes.","hint":"Send a smaller body; upload media with POST /v0/files and send its file_id instead of inlining it.","doc_url":"https://api.flow.engineer/docs/errors/invalid_request"}}}},"exampleType":"examples"}},"exampleType":"examples"},"d112f5b0-489c-479e-8c6c-7e9789892f50":{"description":"The conversation's channel does not take this kind, field, block or value,\nso nothing was sent (`unsupported_content`). `param` names what was\nrefused, `channel` the channel, and `hint` what to send instead.\n","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":{"type":"unsupported_content","channel":"telegram","param":"kind","message":"Carousels work on WhatsApp only.","hint":"On Telegram, send a basic message, then one buttons message with an image header per card.","doc_url":"https://api.flow.engineer/docs/errors/unsupported_content","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"}},"examples":{"Example":{"title":"Example","value":{"error":{"type":"unsupported_content","channel":"telegram","param":"kind","message":"Carousels work on WhatsApp only.","hint":"On Telegram, send a basic message, then one buttons message with an image header per card.","doc_url":"https://api.flow.engineer/docs/errors/unsupported_content","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"}}}},"exampleType":"examples"}},"exampleType":"examples"},"36bbb39b-50a4-429c-9eec-ded81ace924e":{"description":"Too many requests (`rate_limited`): either this key's request limit (see the\n`RateLimit-*` headers) or the sender's sending rate (pacing) was exceeded;\nretry after `Retry-After` seconds (also `error.retry_after`) with the same\n`Idempotency-Key`. Or the sender has used its budget for starting\nconversations (`new_contact_limit`), or the sender is throttled after abuse\nsignals (`sender_throttled`); wait `retry_after` seconds.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}},"RateLimit-Limit":{"description":"Requests allowed in the current window for this key.","schema":{"type":"integer"}},"RateLimit-Remaining":{"description":"Requests left in the current window for this key.","schema":{"type":"integer"}},"RateLimit-Reset":{"description":"Seconds until the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"example":{"error":{"type":"new_contact_limit","message":"This sender has started its 15 new conversations for today.","hint":"Retry after 3600 seconds; replies into existing conversations still go.","doc_url":"https://api.flow.engineer/docs/errors/new_contact_limit","retry_after":3600,"sender":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"}},"examples":{"Example":{"title":"Example","value":{"error":{"type":"new_contact_limit","message":"This sender has started its 15 new conversations for today.","hint":"Retry after 3600 seconds; replies into existing conversations still go.","doc_url":"https://api.flow.engineer/docs/errors/new_contact_limit","retry_after":3600,"sender":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"}}}},"exampleType":"examples"}},"exampleType":"examples"},"f1a15763-f5bc-4fd2-9038-c7d18e3c64bd":{"description":"An error. `error.type` says which (see `ErrorType`).","content":{"application/json":{"schema":{"type":"object","description":"The body of every error answer.","required":["error"],"properties":{"error":{"type":"object","description":"The details of an error.","required":["type","message","hint","doc_url"],"properties":{"type":{"type":"string","description":"What went wrong. A closed list: new types arrive only with a new API version.\nEach type has a page at `https://api.flow.engineer/docs/errors/\u003ctype>`, given in\nthe error's `doc_url`; the error's `hint` says what to change for the case.\n\n- `invalid_request` (400, or 413 for a request body over the size limit): the request is malformed or a parameter is invalid. Fix the parameter named in `param`; the `hint` says what it must look like. Every endpoint answers it for a `Flow-Version` header that is not a version this API serves.\n- `authentication` (401): the API key is missing, malformed, unknown, revoked or expired. An `Authorization: Bearer` header with nothing after it usually means the environment variable holding the key was empty when the header was built (for an MCP client, when the server was added): the `hint` says so. Send `Authorization: Bearer fk_test_...` or `fk_live_...` with a current key; with no key at all, get a test key with `POST /v0/sandbox/keys`. A sandbox key past its `expires_at` has `channel_code` `sandbox_key_expired`: sign in to claim the app, or get a new key.\n- `permission` (403): the key may not do this, for example a test key using a live sender, a sandbox contact who joined another app, a new conversation from an iMessage line that may only reply, or a send past the app's sandbox allowance (`channel_code` `sandbox_allowance_used`, `sandbox_contact_limit` or `sandbox_channel_not_included`). Use the key of the right mode, have the contact send your join message, wait for the contact to message the line first, or sign in through the device flow to lift the allowance. On SMS: `contact_opted_out` (the contact texted STOP; nothing more goes to them until they text START), `consent_required` (a start to someone who never texted your numbers: record their consent with `consent` on the start). In a HIPAA account: `hipaa_channel_not_covered` (the channel has no business associate agreement; use SMS). Simulated conversations: `simulated_contact` (a real sender was pointed at a simulated contact; reply in the contact's simulated conversation), `not_simulated` (a simulated sender or test endpoint was pointed at a real contact), `test_mode_only`, `simulated_conversation_limit`. In `message.failed`: `sandbox_contact_left` (the contact joined another app on the sandbox sender while the message was queued; have them send your join message again).\n- `not_found` (404): no such object for this app and mode. Check the ID's prefix and that it was made with a key of the same mode (test and live data are separate).\n- `idempotency_conflict` (409): the idempotency key was used for a different request (`channel_code` `body_mismatch`: use a new key), or that request is still running (`in_progress`: wait `retry_after` seconds and repeat it with the same key), or it already created a secret that is shown only once (`secret_not_kept`: creating a webhook endpoint, rotating its secret, connecting a WhatsApp number; a secret that was lost must be rotated again, and a WhatsApp number connected again to see its verify token).\n- `outside_window` (409, or in `message.failed`): the channel will not deliver outside its conversation window. On WhatsApp the 24-hour window is closed: send a template (`POST /v0/conversations/{conversation_id}/template`, or `POST /v0/messages` with `kind` `template` to start), or wait for the contact to write. On iMessage the contact has not messaged the line (or opted in) yet, or not recently, so the failure arrives as a `message.failed` event: wait for the contact to write, then reply in that conversation. Typing and read receipts answer `409 outside_window` directly when the channel's window for them is closed (iMessage typing works only within 5 minutes of the contact's last message; WhatsApp read receipts go at any time); ignore it and send your reply. On SMS, `channel_code` `quiet_hours`: the contact has not texted in the last hour and it is inside the sender's quiet hours in their time zone; retry after `retry_after` seconds, or wait for them to text. In `message.failed`: `window_closed` (WhatsApp's 24-hour window closed while the message was queued; send a template) and `queued_too_long` (the message waited in the queue longer than its sender allows, for example while the sender was paused; send it again if it still applies).\n- `unsupported_content` (422): the conversation's channel does not take this kind, field, block or value, and nothing was sent; Flow never converts a message. `param` names what was refused: `kind` (the endpoint's kind is not on this channel, such as a carousel on Telegram), a field or block (`reply_to` on SMS, `telegram` on WhatsApp, `telegram.is_big`), or the field whose value is not taken (`emoji` outside Telegram's reaction emoji, `buttons` for more than 3 WhatsApp buttons). `channel` is the conversation's channel and `hint` says what to send instead over plain HTTP; each endpoint's page lists its channels. In an iMessage group conversation, a reaction, typing or a read receipt answers it with `param` `kind` and `channel_code` `group_unsupported`: leave it out. Media to an SMS number without MMS answers it with `param` `media` and `channel_code` `no_mms`. An edit or unsend of an iMessage message that went by SMS or RCS (its `network`) answers it with `channel_code` `not_on_sms`: send a new message instead. An edit or unsend past the channel's time limit answers it with `channel_code` `edit_window_closed` or `unsend_window_closed` (iMessage: edits within 15 minutes of sending, unsends within 2 minutes; Telegram: unsends within 48 hours), and an iMessage edit of the message that started the conversation with `first_message_not_editable`; `message` states the limit and how long ago the message was sent. Send a new message instead. `POST /v0/files` answers it for a type Flow does not take (programs, web pages, unknown types). A send by `file_id` of a document a contact sent before Flow malware-scanned documents answers it too: Flow sends only documents it scanned.\n- `new_contact_limit` (429): the sender has used its budget for starting conversations. Wait `retry_after` seconds; replies into existing conversations still go.\n- `sender_throttled` (429): abuse signals tripped (the same text to many new contacts, many starts with no reply, blocks), so the sender may not start conversations until `retry_after`; replies into existing conversations still go. Personalise first messages and start only conversations people expect.\n- `file_blocked` (422): the file failed the malware scan and was not stored. Send a different file. (When the scan cannot run at all, the upload answers a retryable `500 api_error` with `Retry-After` instead.)\n- `rate_limited` (429): either too many requests for this key (the per-key request limit, reported in the `RateLimit-*` headers) or sends faster than the sender's sending rate (pacing). Wait `Retry-After` (`retry_after`) seconds and retry with the same `Idempotency-Key`.\n- `channel_error` (502, or in `message.failed`): the channel refused or failed the message, or timed out; `channel_code` carries its own code. Read `message`, change what the channel objected to, and send again. From typing and read receipts, which call the channel at once, it is safe to ignore. SMS codes are Flow's, the same whichever carrier network carries the message: `carrier_filtered` (a carrier's spam filter blocked it: make it read like a person's message, no shortened links), `unreachable`, `invalid_number`, `landline`, `registration_required` (the number's 10DLC or toll-free registration is not approved yet), `carrier_error`, and `provider_not_configured` (the SMS sender is not fully set up on Flow's side, so nothing was sent; contact the Flow team). Flow's own codes on every channel: `channel_timeout_unknown_outcome` (in `message.failed`: the channel did not answer after the message was sent, and the resends its policy allows did not settle it, so the message may have arrived or not; check with the contact before sending it again) and `unknown_outcome` (from typing and read receipts: the call timed out after it was sent).\n- `not_implemented` (501): this endpoint or channel is not live yet during the beta. Use a channel that is live (Telegram, iMessage), or check the changelog.\n- `api_error` (500, 503): something went wrong on Flow's side. Retry with the same idempotency key after `retry_after` seconds, and quote `request_id` if it persists.\n","enum":["invalid_request","authentication","permission","not_found","idempotency_conflict","outside_window","unsupported_content","new_contact_limit","sender_throttled","file_blocked","rate_limited","channel_error","not_implemented","api_error"],"isRequired":true,"uniqueKey":"error.type","typeLabel":"enum\u003cstring>"},"message":{"type":"string","description":"A sentence for a developer saying what went wrong. Do not parse it; switch on `type`.","isRequired":true,"uniqueKey":"error.message","typeLabel":"string"},"hint":{"type":"string","description":"One sentence saying what to change to make the request succeed, specific\nto this case, for example \"Send a template instead: POST\n/v0/conversations/{conversation_id}/template.\" For `unsupported_content`\nit says what to send instead over plain HTTP. Written for developers and\ncoding agents alike. Do not parse it; it may be reworded at any time.\n","examples":["Send a template instead: POST /v0/conversations/{conversation_id}/template."],"isRequired":true,"uniqueKey":"error.hint","typeLabel":"string"},"doc_url":{"type":"string","format":"uri","description":"The documentation page for this error's type, `https://api.flow.engineer/docs/errors/\u003ctype>`. It says what the error means, why it happens and how to fix it, with code.","examples":["https://api.flow.engineer/docs/errors/outside_window"],"isRequired":true,"uniqueKey":"error.doc_url","typeLabel":"string\u003curi>"},"param":{"type":"string","description":"The request parameter the error is about, as a dotted path (`kind`, `telegram.is_big`, `buttons`, `cards[1].header.type`, `limit`).","uniqueKey":"error.param","typeLabel":"string"},"retry_after":{"type":"integer","minimum":0,"description":"Seconds to wait before retrying, for errors that clear by themselves.","uniqueKey":"error.retry_after","typeLabel":"integer"},"channel":{"type":"string","description":"The conversation's channel, on errors about what it takes (`unsupported_content`) and its windows (`outside_window`).","enum":["telegram","whatsapp","imessage","sms"],"uniqueKey":"error.channel","typeLabel":"enum\u003cstring>"},"conversation":{"type":"string","description":"A conversation ID, `conv_` and a ULID.","pattern":"^conv_[0-9A-HJKMNP-TV-Z]{26}$","examples":["conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1"],"uniqueKey":"error.conversation","typeLabel":"string"},"sender":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"uniqueKey":"error.sender","typeLabel":"string"},"channel_code":{"type":"string","description":"For `channel_error`, the channel's own error code, as given by the\nchannel. For some other errors, Flow's own code naming the case, for\nexample `sandbox_allowance_used` (`permission`: the sandbox allowance is\nused up), `sandbox_contact_limit` (`permission`: the allowance has no\nroom for another contact), `sandbox_channel_not_included` (`permission`:\nthe allowance does not cover this sandbox channel), `sign_in_required`\n(`permission`: an app made without an account cannot do this) or\n`sandbox_key_expired` (`authentication`: a key from `POST\n/v0/sandbox/keys` passed its `expires_at`; `permission`, for a send\nthat carries no key, such as a reply in a webhook answer, from such an\napp). For `idempotency_conflict`, always one of `body_mismatch` (the\nkey was used for a different request), `in_progress` (the first\nrequest is still running; `retry_after` says when to repeat it) or\n`secret_not_kept` (its answer carried a secret shown only once).\nSMS: `contact_opted_out` and `consent_required` (`permission`),\n`quiet_hours` (`outside_window`, with `retry_after`), and\n`carrier_filtered`, `unreachable`, `invalid_number`, `landline`,\n`registration_required`, `carrier_error` and `provider_not_configured`\n(`channel_error`). HIPAA accounts: `hipaa_channel_not_covered`\n(`permission`). Connecting your own WhatsApp number (`POST\n/v0/senders`): `whatsapp_token_malformed`, `whatsapp_token_rejected`,\n`whatsapp_app_secret_malformed` and `whatsapp_number_not_in_account`\n(`invalid_request`), and `whatsapp_number_taken`,\n`whatsapp_account_taken` and `whatsapp_number_managed` (`permission`).\nSimulated conversations (`permission`): `test_mode_only`,\n`not_simulated`, `simulated_contact` and `simulated_conversation_limit`.\nFor a message that failed after it was queued (`message.failed`):\n`sandbox_contact_left` (`permission`), `window_closed` and\n`queued_too_long` (`outside_window`), and\n`channel_timeout_unknown_outcome` (`channel_error`: the channel never\nconfirmed the send, so it may or may not have arrived). iMessage\n(`unsupported_content`): `group_unsupported` (a reaction, typing or a\nread receipt in a group conversation; `param` `kind`) and\n`not_on_sms` (an edit or unsend of a message that went by SMS or RCS;\n`param` `kind`). SMS (`unsupported_content`): `no_mms` (media to a\nnumber without MMS; `param` `media`).\nEdits and unsends (`unsupported_content`): `edit_window_closed` and\n`unsend_window_closed` (the message is older than the channel allows\nfor the change) and `first_message_not_editable` (iMessage: the message\nthat started the conversation). From typing and\nread receipts, `unknown_outcome` (`channel_error`: the call timed out after\nit was sent).\n","uniqueKey":"error.channel_code","typeLabel":"string"},"request_id":{"type":"string","description":"Flow's ID for this request. Quote it when asking for help.","uniqueKey":"error.request_id","typeLabel":"string"}},"isRequired":true,"uniqueKey":"error","typeLabel":"object"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"error":{"type":"invalid_request","message":"\u003cstring>","hint":"Send a template instead: POST /v0/conversations/{conversation_id}/template.","doc_url":"https://api.flow.engineer/docs/errors/outside_window","param":"\u003cstring>","retry_after":1,"channel":"telegram","conversation":"conv_01JB8ZC3K5M7P9R1T3V5X7Z9B1","sender":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T","channel_code":"\u003cstring>","request_id":"\u003cstring>"}}}},"exampleType":"generated"}},"exampleType":"generated"}},"security":{"59c5f960-0d19-49e7-944f-bfe75a0ffe7d":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"fk_test_... or fk_live_...","description":"An API key of one app, sent as `Authorization: Bearer \u003ckey>`. Keys start with\n`fk_test_` (test mode: sandbox senders and test data only) or `fk_live_`\n(live mode). Keep live keys on your server; never ship them in an app or page.\n","scopes":[],"schemeName":"bearerAuth"}}},"servers":{"90a9657d-20c1-4182-87ad-a4d557fcda08":{"url":"https://api.flow.engineer","description":"Production. Test and live mode are chosen by the API key."}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"fk_test_... or fk_live_...","description":"An API key of one app, sent as `Authorization: Bearer \u003ckey>`. Keys start with\n`fk_test_` (test mode: sandbox senders and test data only) or `fk_live_`\n(live mode). Keep live keys on your server; never ship them in an app or page.\n","scopes":[],"schemeName":"bearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"An API key of one app, sent as `Authorization: Bearer \u003ckey>`. Keys start with\n`fk_test_` (test mode: sandbox senders and test data only) or `fk_live_`\n(live mode). Keep live keys on your server; never ship them in an app or page.\n","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"bearerAuth","name":"Authorization"}],"title":"bearerAuth"}]},"originalFileLocation":"unified-messaging-api/openapi.yaml"},"subdomain":"flow-messaging","siteName":"Flow","title":"Send a basic message (text, or media with a caption) - Flow","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-24T16:17:31.202Z","originalFileLocation":"api-reference/messages/send-a-basic-message-text-or-media-with-a-caption.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=\"| Channel | Works | Limits | |---|---|---| | Telegram | Yes | text 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; media.filename only with file_id (Telegram names a document sent by url itself) | | WhatsApp | Yes | text 4096 characters; a caption 1024 (none on audio: text with media.type audio is refused, send the text as its own message); files up to 100 MB | | iMessage | Yes | text 9999 characters; a caption 1024; files up to 100 MB | | SMS (US, pilot) | Yes | text at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see SmsSegments); media only from numbers with MMS (Sender.sms.mms): images, audio and video up to 5 MB, no documents | Sends text, or one image, video, document or audio file with an optional caption, into an existing conversation. This is the normal way to reply to a contact, and the one kind every channel takes. The send passes the send gate (window rules, pacing) and is queued; the answer is the queued message. Its progress arrives as message.sent, message.delivered, message.read or message.failed events. Sends to one conversation go out in the order they were accepted (see \u0026quot;Order and duplicates\u0026quot;). text is sent exactly as written: Flow never reads it as markdown, never strips or converts marks, and never warns. WhatsApp\u0026#x27;s app shows its own marks (bold, italic) as styles by itself. To style text on Telegram or iMessage, use that channel\u0026#x27;s block: telegram.parse_mode (Telegram\u0026#x27;s own HTML or MarkdownV2) or imessage.styles (ranges of the text). On iMessage, text that looks like markup still shows as written. A field or block a channel does not take is refused, never ignored: a telegram block sent to a WhatsApp conversation answers 422 unsupported_content with param telegram, reply_to on SMS with param reply_to, link_preview: true on SMS with param link_preview. A field this endpoint does not know answers 400 invalid_request naming it in param. media to an SMS number without MMS answers 422 unsupported_content with param media and channel_code no_mms; a document on SMS with param media.type; a file larger than the channel takes with param media. iMessage lines with the SMS/RCS add-on (Sender.imessage.fallback): a message to a contact who cannot get iMessage goes by SMS or RCS. The network is chosen for each message when it is sent, never by your app, and the message\u0026#x27;s network (also data.message.network in its events) says which one carried it. A message that went by SMS or RCS shows no imessage.styles, no imessage.subject and no effect, and cannot be edited or unsent (422 unsupported_content, channel_code not_on_sms). There are no scheduled sends: a message goes out as soon as it passes the gate, so to send later, wait in your own code and send then.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Flow\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/flow-messaging/_generated/favicon/apple-touch-icon.png?v=3\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/flow-messaging/_generated/favicon/favicon-32x32.png?v=3\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/flow-messaging/_generated/favicon/favicon-16x16.png?v=3\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"https://mintlify.s3.us-west-1.amazonaws.com/flow-messaging/_generated/favicon/favicon.ico?v=3\">\u003cmeta data-mint-head property=\"og:title\" content=\"Send a basic message (text, or media with a caption) - Flow\">\u003cmeta data-mint-head property=\"og:description\" content=\"| Channel | Works | Limits | |---|---|---| | Telegram | Yes | text 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; media.filename only with file_id (Telegram names a document sent by url itself) | | WhatsApp | Yes | text 4096 characters; a caption 1024 (none on audio: text with media.type audio is refused, send the text as its own message); files up to 100 MB | | iMessage | Yes | text 9999 characters; a caption 1024; files up to 100 MB | | SMS (US, pilot) | Yes | text at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see SmsSegments); media only from numbers with MMS (Sender.sms.mms): images, audio and video up to 5 MB, no documents | Sends text, or one image, video, document or audio file with an optional caption, into an existing conversation. This is the normal way to reply to a contact, and the one kind every channel takes. The send passes the send gate (window rules, pacing) and is queued; the answer is the queued message. Its progress arrives as message.sent, message.delivered, message.read or message.failed events. Sends to one conversation go out in the order they were accepted (see \u0026quot;Order and duplicates\u0026quot;). text is sent exactly as written: Flow never reads it as markdown, never strips or converts marks, and never warns. WhatsApp\u0026#x27;s app shows its own marks (bold, italic) as styles by itself. To style text on Telegram or iMessage, use that channel\u0026#x27;s block: telegram.parse_mode (Telegram\u0026#x27;s own HTML or MarkdownV2) or imessage.styles (ranges of the text). On iMessage, text that looks like markup still shows as written. A field or block a channel does not take is refused, never ignored: a telegram block sent to a WhatsApp conversation answers 422 unsupported_content with param telegram, reply_to on SMS with param reply_to, link_preview: true on SMS with param link_preview. A field this endpoint does not know answers 400 invalid_request naming it in param. media to an SMS number without MMS answers 422 unsupported_content with param media and channel_code no_mms; a document on SMS with param media.type; a file larger than the channel takes with param media. iMessage lines with the SMS/RCS add-on (Sender.imessage.fallback): a message to a contact who cannot get iMessage goes by SMS or RCS. The network is chosen for each message when it is sent, never by your app, and the message\u0026#x27;s network (also data.message.network in its events) says which one carried it. A message that went by SMS or RCS shows no imessage.styles, no imessage.subject and no effect, and cannot be edited or unsent (422 unsupported_content, channel_code not_on_sms). There are no scheduled sends: a message goes out as soon as it passes the gate, so to send later, wait in your own code and send then.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Flow\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://flow-messaging.mintlify.app/_mintlify/api/og/v2?division=Messages\u0026amp;title=Send+a+basic+message+%28text%2C+or+media+with+a+caption%29\u0026amp;description=%7C+Channel+%7C+Works+%7C+Limits+%7C%0A%7C---%7C---%7C---%7C%0A%7C+Telegram+%7C+Yes+%7C+%60text%60+4096+UTF-16+code+units+%28an+emoji+such+as+%F0%9F%98%80+counts+as+2%29%3B+a+caption+1024%3B+files+up+to+50+MB%3B\u0026amp;theme=052dec2df14a3094abf38032\u0026amp;signature=0aff6560d795dff41cc97d838486f65d3329f0188ac26d05fb97737d5029af02\">\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 a basic message (text, or media with a caption) - Flow\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"| Channel | Works | Limits | |---|---|---| | Telegram | Yes | text 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; media.filename only with file_id (Telegram names a document sent by url itself) | | WhatsApp | Yes | text 4096 characters; a caption 1024 (none on audio: text with media.type audio is refused, send the text as its own message); files up to 100 MB | | iMessage | Yes | text 9999 characters; a caption 1024; files up to 100 MB | | SMS (US, pilot) | Yes | text at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see SmsSegments); media only from numbers with MMS (Sender.sms.mms): images, audio and video up to 5 MB, no documents | Sends text, or one image, video, document or audio file with an optional caption, into an existing conversation. This is the normal way to reply to a contact, and the one kind every channel takes. The send passes the send gate (window rules, pacing) and is queued; the answer is the queued message. Its progress arrives as message.sent, message.delivered, message.read or message.failed events. Sends to one conversation go out in the order they were accepted (see \u0026quot;Order and duplicates\u0026quot;). text is sent exactly as written: Flow never reads it as markdown, never strips or converts marks, and never warns. WhatsApp\u0026#x27;s app shows its own marks (bold, italic) as styles by itself. To style text on Telegram or iMessage, use that channel\u0026#x27;s block: telegram.parse_mode (Telegram\u0026#x27;s own HTML or MarkdownV2) or imessage.styles (ranges of the text). On iMessage, text that looks like markup still shows as written. A field or block a channel does not take is refused, never ignored: a telegram block sent to a WhatsApp conversation answers 422 unsupported_content with param telegram, reply_to on SMS with param reply_to, link_preview: true on SMS with param link_preview. A field this endpoint does not know answers 400 invalid_request naming it in param. media to an SMS number without MMS answers 422 unsupported_content with param media and channel_code no_mms; a document on SMS with param media.type; a file larger than the channel takes with param media. iMessage lines with the SMS/RCS add-on (Sender.imessage.fallback): a message to a contact who cannot get iMessage goes by SMS or RCS. The network is chosen for each message when it is sent, never by your app, and the message\u0026#x27;s network (also data.message.network in its events) says which one carried it. A message that went by SMS or RCS shows no imessage.styles, no imessage.subject and no effect, and cannot be edited or unsent (422 unsupported_content, channel_code not_on_sms). There are no scheduled sends: a message goes out as soon as it passes the gate, so to send later, wait in your own code and send then.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://flow-messaging.mintlify.app/_mintlify/api/og/v2?division=Messages\u0026amp;title=Send+a+basic+message+%28text%2C+or+media+with+a+caption%29\u0026amp;description=%7C+Channel+%7C+Works+%7C+Limits+%7C%0A%7C---%7C---%7C---%7C%0A%7C+Telegram+%7C+Yes+%7C+%60text%60+4096+UTF-16+code+units+%28an+emoji+such+as+%F0%9F%98%80+counts+as+2%29%3B+a+caption+1024%3B+files+up+to+50+MB%3B\u0026amp;theme=052dec2df14a3094abf38032\u0026amp;signature=0aff6560d795dff41cc97d838486f65d3329f0188ac26d05fb97737d5029af02\">\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=\"https://mintlify.s3.us-west-1.amazonaws.com/flow-messaging/_generated/favicon/browserconfig.xml?v=3\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Flow\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#0b7a5a\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.flow.engineer/#organization\",\"name\":\"Flow\",\"url\":\"https://docs.flow.engineer\"},{\"@type\":\"WebSite\",\"@id\":\"https://docs.flow.engineer#website\",\"name\":\"Flow\",\"url\":\"https://docs.flow.engineer\",\"publisher\":{\"@id\":\"https://docs.flow.engineer/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption#webpage\",\"url\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption\",\"name\":\"Send a basic message (text, or media with a caption)\",\"description\":\"| Channel | Works | Limits | |---|---|---| | Telegram | Yes | text 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; media.filename only with file_id (Telegram names a document sent by url itself) | | WhatsApp | Yes | text 4096 characters; a caption 1024 (none on audio: text with media.type audio is refused, send the text as its own message); files up to 100 MB | | iMessage | Yes | text 9999 characters; a caption 1024; files up to 100 MB | | SMS (US, pilot) | Yes | text at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see SmsSegments); media only from numbers with MMS (Sender.sms.mms): images, audio and video up to 5 MB, no documents | Sends text, or one image, video, document or audio file with an optional caption, into an existing conversation. This is the normal way to reply to a contact, and the one kind every channel takes. The send passes the send gate (window rules, pacing) and is queued; the answer is the queued message. Its progress arrives as message.sent, message.delivered, message.read or message.failed events. Sends to one conversation go out in the order they were accepted (see \\\"Order and duplicates\\\"). text is sent exactly as written: Flow never reads it as markdown, never strips or converts marks, and never warns. WhatsApp's app shows its own marks (bold, italic) as styles by itself. To style text on Telegram or iMessage, use that channel's block: telegram.parse_mode (Telegram's own HTML or MarkdownV2) or imessage.styles (ranges of the text). On iMessage, text that looks like markup still shows as written. A field or block a channel does not take is refused, never ignored: a telegram block sent to a WhatsApp conversation answers 422 unsupported_content with param telegram, reply_to on SMS with param reply_to, link_preview: true on SMS with param link_preview. A field this endpoint does not know answers 400 invalid_request naming it in param. media to an SMS number without MMS answers 422 unsupported_content with param media and channel_code no_mms; a document on SMS with param media.type; a file larger than the channel takes with param media. iMessage lines with the SMS/RCS add-on (Sender.imessage.fallback): a message to a contact who cannot get iMessage goes by SMS or RCS. The network is chosen for each message when it is sent, never by your app, and the message's network (also data.message.network in its events) says which one carried it. A message that went by SMS or RCS shows no imessage.styles, no imessage.subject and no effect, and cannot be edited or unsent (422 unsupported_content, channel_code not_on_sms). There are no scheduled sends: a message goes out as soon as it passes the gate, so to send later, wait in your own code and send then.\",\"dateModified\":\"2026-10-24T16:17:31.202Z\",\"isPartOf\":{\"@id\":\"https://docs.flow.engineer#website\"},\"breadcrumb\":{\"@id\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"HTTP API\",\"item\":\"https://docs.flow.engineer/unified-messaging-api/api-reference/introduction\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Send a basic message (text, or media with a caption)\",\"item\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption#apireference\",\"headline\":\"Send a basic message (text, or media with a caption)\",\"name\":\"Send a basic message (text, or media with a caption)\",\"description\":\"| Channel | Works | Limits | |---|---|---| | Telegram | Yes | text 4096 UTF-16 code units (an emoji such as 😀 counts as 2); a caption 1024; files up to 50 MB; media.filename only with file_id (Telegram names a document sent by url itself) | | WhatsApp | Yes | text 4096 characters; a caption 1024 (none on audio: text with media.type audio is refused, send the text as its own message); files up to 100 MB | | iMessage | Yes | text 9999 characters; a caption 1024; files up to 100 MB | | SMS (US, pilot) | Yes | text at most 10 segments (1530 GSM-7 characters, 670 with an emoji or other character outside GSM-7; see SmsSegments); media only from numbers with MMS (Sender.sms.mms): images, audio and video up to 5 MB, no documents | Sends text, or one image, video, document or audio file with an optional caption, into an existing conversation. This is the normal way to reply to a contact, and the one kind every channel takes. The send passes the send gate (window rules, pacing) and is queued; the answer is the queued message. Its progress arrives as message.sent, message.delivered, message.read or message.failed events. Sends to one conversation go out in the order they were accepted (see \\\"Order and duplicates\\\"). text is sent exactly as written: Flow never reads it as markdown, never strips or converts marks, and never warns. WhatsApp's app shows its own marks (bold, italic) as styles by itself. To style text on Telegram or iMessage, use that channel's block: telegram.parse_mode (Telegram's own HTML or MarkdownV2) or imessage.styles (ranges of the text). On iMessage, text that looks like markup still shows as written. A field or block a channel does not take is refused, never ignored: a telegram block sent to a WhatsApp conversation answers 422 unsupported_content with param telegram, reply_to on SMS with param reply_to, link_preview: true on SMS with param link_preview. A field this endpoint does not know answers 400 invalid_request naming it in param. media to an SMS number without MMS answers 422 unsupported_content with param media and channel_code no_mms; a document on SMS with param media.type; a file larger than the channel takes with param media. iMessage lines with the SMS/RCS add-on (Sender.imessage.fallback): a message to a contact who cannot get iMessage goes by SMS or RCS. The network is chosen for each message when it is sent, never by your app, and the message's network (also data.message.network in its events) says which one carried it. A message that went by SMS or RCS shows no imessage.styles, no imessage.subject and no effect, and cannot be edited or unsent (422 unsupported_content, channel_code not_on_sms). There are no scheduled sends: a message goes out as soon as it passes the gate, so to send later, wait in your own code and send then.\",\"url\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption\",\"mainEntityOfPage\":{\"@id\":\"https://docs.flow.engineer/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption#webpage\"},\"dateModified\":\"2026-10-24T16:17:31.202Z\",\"publisher\":{\"@id\":\"https://docs.flow.engineer/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.flow.engineer#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Flow\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Flow","nav":{"global":null,"tabs":[{"tab":"Framework","pages":[{"title":"Framework","href":"/framework"}]},{"tab":"Messaging API","groups":[{"group":"Get started","pages":[{"title":"Unified Messaging API","sidebarTitle":"Introduction","icon":"comments","href":"/unified-messaging-api"},{"title":"Send your first reply","sidebarTitle":"Quickstart","icon":"rocket","href":"/unified-messaging-api/quickstart"},{"title":"Keys and sign-in","sidebarTitle":"Keys \u0026 sign-in","icon":"key","href":"/unified-messaging-api/get-a-key"},{"title":"Build with a coding agent","sidebarTitle":"For coding agents","icon":"robot","href":"/unified-messaging-api/coding-agents"},{"title":"Build for real conversations","sidebarTitle":"Real conversations","icon":"users","href":"/unified-messaging-api/guides/real-people"},{"title":"Messaging MCP server","sidebarTitle":"Development MCP","icon":"plug","href":"/unified-messaging-api/mcp"},{"title":"Pricing and allowances","sidebarTitle":"Pricing","icon":"credit-card","href":"/unified-messaging-api/pricing"}]},{"group":"Observe","pages":[{"title":"Observe conversations","sidebarTitle":"Overview","icon":"eye","href":"/unified-messaging-api/observe/index"},{"title":"Connect Messaging to Observe","sidebarTitle":"Messaging integration","icon":"comments","href":"/unified-messaging-api/observe/flow-messaging"},{"title":"Send traces to Observe","sidebarTitle":"Traces","icon":"chart-line","href":"/unified-messaging-api/observe/traces"},{"title":"Trace your agent framework","sidebarTitle":"Framework integrations","icon":"diagram-project","href":"/unified-messaging-api/observe/frameworks"}]},{"group":"Test before you ship","pages":[{"title":"Test your integration","sidebarTitle":"Testing","icon":"flask","href":"/unified-messaging-api/trust"}]},{"group":"Concepts","pages":[{"title":"Connect a sender","sidebarTitle":"Senders","icon":"phone","href":"/unified-messaging-api/concepts/senders"},{"title":"Conversations and contacts","sidebarTitle":"Conversations","icon":"comments","href":"/unified-messaging-api/concepts/conversations"},{"title":"Send text, media and buttons","sidebarTitle":"Message kinds","icon":"shapes","href":"/unified-messaging-api/concepts/content-types"},{"title":"Receive events","sidebarTitle":"Events \u0026 webhooks","icon":"webhook","href":"/unified-messaging-api/concepts/events-and-webhooks"},{"title":"Stream replies","sidebarTitle":"Streaming replies","icon":"water","href":"/unified-messaging-api/concepts/streaming-replies"},{"title":"Sending rules","sidebarTitle":"Sending rules","icon":"shield-check","href":"/unified-messaging-api/concepts/send-gate"},{"title":"Test and live mode","sidebarTitle":"Test \u0026 live mode","icon":"toggle-on","href":"/unified-messaging-api/concepts/test-and-live-mode"},{"title":"Retry without duplicate sends","sidebarTitle":"Idempotency","icon":"repeat","href":"/unified-messaging-api/concepts/idempotency"},{"title":"Retention and deletion","sidebarTitle":"Retention \u0026 deletion","icon":"database","href":"/unified-messaging-api/concepts/data-retention"},{"title":"API versions","sidebarTitle":"Versioning","icon":"code-branch","href":"/unified-messaging-api/concepts/versioning"},{"title":"Rate limits","sidebarTitle":"Rate limits","icon":"gauge","href":"/unified-messaging-api/concepts/rate-limits"}]},{"group":"Channel guides","pages":[{"title":"Telegram","sidebarTitle":"Telegram","icon":"telegram","href":"/unified-messaging-api/guides/telegram-agent"},{"title":"iMessage","sidebarTitle":"iMessage","icon":"message","href":"/unified-messaging-api/guides/imessage-agent"},{"title":"WhatsApp","sidebarTitle":"WhatsApp","icon":"whatsapp","href":"/unified-messaging-api/guides/whatsapp-agent"},{"title":"Local development","sidebarTitle":"Local development","icon":"laptop-code","href":"/unified-messaging-api/guides/local-development"},{"title":"Go live","sidebarTitle":"Going live","icon":"flag-checkered","href":"/unified-messaging-api/guides/going-live"},{"title":"Messaging recipes","sidebarTitle":"Recipes","icon":"book-open","href":"/unified-messaging-api/guides/recipes"}]},{"group":"Agent frameworks","pages":[{"title":"Vercel AI SDK","sidebarTitle":"Vercel AI SDK","icon":"code","href":"/unified-messaging-api/frameworks/vercel-ai-sdk"},{"title":"OpenAI Agents SDK","sidebarTitle":"OpenAI Agents SDK","icon":"code","href":"/unified-messaging-api/frameworks/openai-agents-sdk"},{"title":"Claude Agent SDK","sidebarTitle":"Claude Agent SDK","icon":"code","href":"/unified-messaging-api/frameworks/claude-agent-sdk"},{"title":"LangChain","sidebarTitle":"LangChain","icon":"link","href":"/unified-messaging-api/frameworks/langchain"},{"title":"Mastra","sidebarTitle":"Mastra","icon":"code","href":"/unified-messaging-api/frameworks/mastra"}]},{"group":"Compare","pages":[{"title":"Choose a messaging API","sidebarTitle":"Choose an API","icon":"scale-balanced","href":"/unified-messaging-api/compare/choosing-a-messaging-api"},{"title":"Flow and Photon","sidebarTitle":"Flow vs Photon","icon":"scale-balanced","href":"/unified-messaging-api/compare/flow-vs-photon"}]},{"group":"HTTP API","pages":[{"group":"Overview","expanded":false,"pages":[{"title":"HTTP API","sidebarTitle":"API overview","description":"Authentication, pagination, errors and versioning for the Unified Messaging API.","icon":"code","href":"/unified-messaging-api/api-reference/introduction"}]},{"group":"Messages","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/basic","title":"Send a basic message (text, or media with a caption)","href":"/api-reference/messages/send-a-basic-message-text-or-media-with-a-caption"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/voice","title":"Send a voice note","description":"| Channel | Works | Limits |\n|---|---|---|\n| Telegram | Yes | files up to 50 MB |\n| WhatsApp | Yes | files up to 100 MB |\n| iMessage | Yes | files up to 100 MB |\n| SMS (US, pilot) | No | |\n\nOn SMS, send instead: a basic message with `media` of `type` `audio`\n(from a number with MMS).\n\nSends an audio file as a voice note, shown with the channel's voice note\nplayer. Give `url` (an HTTPS URL Flow fetches) or `file_id` (from `POST\n/v0/files`). A send to SMS answers `422 unsupported_content` with `param`\n`kind`. Sends to one conversation go out in the order they were accepted\n(see \"Order and duplicates\").\n","href":"/api-reference/messages/send-a-voice-note"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/buttons","title":"Send text with buttons","href":"/api-reference/messages/send-text-with-buttons"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/list","title":"Send a list to pick one option from","href":"/api-reference/messages/send-a-list-to-pick-one-option-from"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/carousel","title":"Send a carousel of cards","href":"/api-reference/messages/send-a-carousel-of-cards"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/template","title":"Send a WhatsApp template","href":"/api-reference/messages/send-a-whatsapp-template"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/contact-card","title":"Send a contact card","href":"/api-reference/messages/send-a-contact-card"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/location","title":"Send a place","href":"/api-reference/messages/send-a-place"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/effect","title":"Send text with an iMessage effect","href":"/api-reference/messages/send-text-with-an-imessage-effect"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/reaction","title":"React to a message","href":"/api-reference/messages/react-to-a-message"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/messages","title":"Start a conversation","href":"/api-reference/messages/start-a-conversation"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/messages/{message_id}","title":"Get a message","href":"/api-reference/messages/get-a-message"},{"openapi":"unified-messaging-api/openapi.yaml PATCH /v0/messages/{message_id}","title":"Edit a sent message","href":"/api-reference/messages/edit-a-sent-message"},{"openapi":"unified-messaging-api/openapi.yaml DELETE /v0/messages/{message_id}","title":"Unsend a message","href":"/api-reference/messages/unsend-a-message"}]},{"group":"Conversations","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml GET /v0/conversations","title":"List conversations","href":"/api-reference/conversations/list-conversations"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/conversations/{conversation_id}","title":"Get a conversation","href":"/api-reference/conversations/get-a-conversation"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/conversations/{conversation_id}/messages","title":"List a conversation's messages","href":"/api-reference/conversations/list-a-conversations-messages"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/typing","title":"Show the typing indicator","href":"/api-reference/conversations/show-the-typing-indicator"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/conversations/{conversation_id}/read","title":"Mark messages as read","href":"/api-reference/conversations/mark-messages-as-read"}]},{"group":"Events","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml GET /v0/events","title":"List events","href":"/api-reference/events/list-events"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/events/{event_id}","title":"Get an event","href":"/api-reference/events/get-an-event"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/stream","title":"Open the live event stream (WebSocket)","href":"/api-reference/stream/open-the-live-event-stream-websocket"},{"openapi":"unified-messaging-api/openapi.yaml webhook event","title":"An event delivered to your endpoint","href":"/api-reference/webhook-endpoints/an-event-delivered-to-your-endpoint"}]},{"group":"Webhook endpoints","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml GET /v0/webhook_endpoints","title":"List webhook endpoints","href":"/api-reference/webhook-endpoints/list-webhook-endpoints"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/webhook_endpoints","title":"Create a webhook endpoint","href":"/api-reference/webhook-endpoints/create-a-webhook-endpoint"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/webhook_endpoints/{webhook_endpoint_id}","title":"Get a webhook endpoint","href":"/api-reference/webhook-endpoints/get-a-webhook-endpoint"},{"openapi":"unified-messaging-api/openapi.yaml PATCH /v0/webhook_endpoints/{webhook_endpoint_id}","title":"Update a webhook endpoint","href":"/api-reference/webhook-endpoints/update-a-webhook-endpoint"},{"openapi":"unified-messaging-api/openapi.yaml DELETE /v0/webhook_endpoints/{webhook_endpoint_id}","title":"Delete a webhook endpoint","href":"/api-reference/webhook-endpoints/delete-a-webhook-endpoint"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/webhook_endpoints/{webhook_endpoint_id}/rotate_secret","title":"Rotate a webhook endpoint's signing secret","href":"/api-reference/webhook-endpoints/rotate-a-webhook-endpoints-signing-secret"}]},{"group":"Files","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml POST /v0/files","title":"Upload a file","href":"/api-reference/files/upload-a-file"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/files/{file_id}","title":"Download a file","href":"/api-reference/files/download-a-file"}]},{"group":"Senders and templates","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml GET /v0/senders","title":"List senders","href":"/api-reference/senders/list-senders"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/senders","title":"Request a dedicated sender","href":"/api-reference/senders/request-a-dedicated-sender"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/senders/{sender_id}","title":"Get a sender","href":"/api-reference/senders/get-a-sender"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/templates","title":"List templates","href":"/api-reference/templates/list-templates"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/templates","title":"Create a template","href":"/api-reference/templates/create-a-template"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/templates/{template_id}","title":"Get a template","href":"/api-reference/templates/get-a-template"},{"openapi":"unified-messaging-api/openapi.yaml DELETE /v0/templates/{template_id}","title":"Delete a template","href":"/api-reference/templates/delete-a-template"},{"openapi":"unified-messaging-api/openapi.yaml DELETE /v0/senders/{sender_id}","title":"Disconnect a sender","href":"/api-reference/senders/disconnect-a-sender"}]},{"group":"Contacts and app","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml GET /v0/contacts","title":"List contacts","href":"/api-reference/contacts/list-contacts"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/contacts/{contact_id}","title":"Get a contact","href":"/api-reference/contacts/get-a-contact"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/app","title":"Get the calling app","href":"/api-reference/app/get-the-calling-app"},{"openapi":"unified-messaging-api/openapi.yaml DELETE /v0/contacts/{contact_id}","title":"Delete a contact and their data","href":"/api-reference/contacts/delete-a-contact-and-their-data"}]},{"group":"Onboarding","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml POST /v0/sandbox/keys","title":"Get a test key without an account","href":"/api-reference/onboarding/get-a-test-key-without-an-account"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/device/authorizations","title":"Start a sign-in from an agent or CLI (device flow)","href":"/api-reference/onboarding/start-a-sign-in-from-an-agent-or-cli-device-flow"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/device/token","title":"Poll a device sign-in for its key","href":"/api-reference/onboarding/poll-a-device-sign-in-for-its-key"}]},{"group":"Simulated conversations","expanded":false,"pages":[{"openapi":"unified-messaging-api/openapi.yaml POST /v0/test/conversations","title":"Create a simulated conversation","href":"/api-reference/testing/create-a-simulated-conversation"},{"openapi":"unified-messaging-api/openapi.yaml POST /v0/test/conversations/{conversation_id}/inbound","title":"Write as the simulated contact","href":"/api-reference/testing/write-as-the-simulated-contact"},{"openapi":"unified-messaging-api/openapi.yaml GET /v0/test/conversations/{conversation_id}/transcript","title":"Read a simulated conversation, both ways","href":"/api-reference/testing/read-a-simulated-conversation-both-ways"}]},{"group":"Errors","expanded":false,"pages":[{"title":"invalid_request","href":"/unified-messaging-api/errors/invalid_request"},{"title":"authentication","href":"/unified-messaging-api/errors/authentication"},{"title":"permission","href":"/unified-messaging-api/errors/permission"},{"title":"not_found","href":"/unified-messaging-api/errors/not_found"},{"title":"idempotency_conflict","href":"/unified-messaging-api/errors/idempotency_conflict"},{"title":"outside_window","href":"/unified-messaging-api/errors/outside_window"},{"title":"unsupported_content","href":"/unified-messaging-api/errors/unsupported_content"},{"title":"new_contact_limit","href":"/unified-messaging-api/errors/new_contact_limit"},{"title":"sender_throttled","href":"/unified-messaging-api/errors/sender_throttled"},{"title":"file_blocked","href":"/unified-messaging-api/errors/file_blocked"},{"title":"rate_limited","href":"/unified-messaging-api/errors/rate_limited"},{"title":"channel_error","href":"/unified-messaging-api/errors/channel_error"},{"title":"not_implemented","href":"/unified-messaging-api/errors/not_implemented"},{"title":"api_error","href":"/unified-messaging-api/errors/api_error"}]}]}]}]},"title":"Send a basic message (text, or media with a caption) - Flow","buildId":"dpl_849ArpqvBiCczQiT1Y1stNGpbqHT","deploymentId":"dpl_849ArpqvBiCczQiT1Y1stNGpbqHT","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-Bbp7I60D.js","utils-C3RIvJha.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-DqD-vLt8.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-B31Loprg.js","snippetPresets-DKpk-b8t.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","ApiExamples-Cj65AhOR.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-BXtn5gcC.js","shallow-RY2b03Cp.js","getApiPlaygroundDisplay-B0jeiPk3.js","CodeSnippet-CYgBjjwn.js","CodeSnippets-DOngDrYB.js","Page-n7I5XbKb.js","getPastedJson-DRQbJx-T.js","icon-CQiQCicY.js","MethodPill-BKTLdNtu.js","DuplicateIcon-B9jpAdat.js","createIcon-DCddRrXv.js","DynamicMarkdown-a8hUKrw6.js","SectionHeading-eECVV2eH.js","axios-vUo_bRtp.js","Markdown--GF7ZIpf.js","clsx-DZLdJUrt.js","lib--scc4DXi.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-2LoAhjKH.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-Zwc0ZncM.js"]}