{
"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": "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"
}
}
Disconnects one of your dedicated Telegram bots or WhatsApp numbers from
Flow. For a bot, Flow removes its webhook (best effort) and deletes its
stored token; for a WhatsApp number, Flow deletes its stored token and app
secret and stops taking its webhooks. Either way the sender is retired: its
status becomes banned, it no longer sends or receives, and messages still
queued from it fail. You receive sender.status_changed. The sender, its
conversations and its messages stay readable. Repeating the call is safe and
answers with the retired sender. Nothing changes in your Meta app: remove
Flow’s callback URL there, or point the number elsewhere, yourself.
Live keys only. Shared sandbox senders belong to Flow and cannot be
disconnected (403 permission with a test key). iMessage lines and SMS
numbers, and WhatsApp numbers the Flow team manages for you, are
disconnected by Flow, not by API (501 not_implemented).
To use the bot or number again, connect it with POST /v0/senders; it
becomes a new sender.
{
"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": "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.
The sender is disconnected; it is returned with status banned.
What your agent talks from: a Telegram bot, a WhatsApp number, an iMessage
line or a US SMS number. shared senders are Flow's sandbox, used by many apps in test mode;
dedicated senders are yours alone; simulated senders exist only in test
mode, for simulated conversations. Each sender has its own limits and warm-up
state.
shared (the sandbox), dedicated (yours) or simulated (test mode only:
your app's stand-in for a channel, used by simulated conversations from
POST /v0/test/conversations; it never touches a network).
warming_up: active, with a new-contact budget that grows day by day.
throttled: the gate slowed it after an abuse signal; it recovers by itself.
flagged: the channel or Flow flagged it; starts are paused. A Telegram
bot is also flagged when Telegram rejects its token (revoked in
@BotFather): it then sends nothing, new sends answer 403 permission, and
queued messages wait until you connect the bot again with its new token
(POST /v0/senders). They wait at most 72 hours after Flow accepted
them; older ones fail with outside_window (channel_codequeued_too_long) in message.failed instead of going out late.
banned: it cannot send or receive: the channel banned it, you
disconnected it (DELETE /v0/senders/{sender_id}), or its bot or line was
connected to another app.
SMS senders only: how the number is registered with US carriers and what it
can do. An SMS number stays pending until its registration is approved
(carriers block traffic from unregistered numbers).
Only in the answer to POST /v0/senders that connected a WhatsApp number:
what you still set in your own Meta app, which Flow cannot set for you.
Flow already points the number's webhooks at callback_url (Meta's
phone-number-level override); entering the same URL in your app makes its
field subscriptions apply. The verify token is shown only in this answer
(connecting the number again shows it again); keep it like a password.
Shared senders only. The whole message a contact sends to this sender to join your app: Hi, the app's name (there when it has none), then the app's sandbox_join_code (from GET /v0/app) in brackets after ref, for example Hi Sandbox app (ref brave-otter-40718263). Show it to testers as is; a link that fills it in (wa.me, sms:) carries it URL-encoded. Any message of at most 160 characters that ends with (ref <code>) joins, so a tester may change the words before the brackets.
Example:
"Hi Sandbox app (ref brave-otter-40718263)"
{"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":"6adde04717041bcf74b75bdf","collectionId":"8a3a4852-5d6d-4481-bc3b-5d9509276537","liveDeploymentHistoryId":"6adde04717041bcf74b75bdf","schemaVersion":"v3"},"entitlements":{"AI_CHAT":{"status":"DISABLED"},"WEB_MCP":{"status":"DISABLED"},"NARRATION":{"status":"DISABLED"}},"buildId":"6adde04717041bcf74b75bdf","clientVersion":"0.0.3965","searchFilterCounts":[{"language":"default","tag":"Messaging API","count":100},{"language":"default","tag":"HTTP API","count":64},{"language":"default","tag":"Framework","count":28},{"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/senders/disconnect-a-sender","slug":"/api-reference/senders/disconnect-a-sender","pageMetadata":{"openapi":"unified-messaging-api/openapi.yaml DELETE /v0/senders/{sender_id}","title":"Disconnect a sender","description":"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from\nFlow. For a bot, Flow removes its webhook (best effort) and deletes its\nstored token; for a WhatsApp number, Flow deletes its stored token and app\nsecret and stops taking its webhooks. Either way the sender is retired: its\nstatus becomes `banned`, it no longer sends or receives, and messages still\nqueued from it fail. You receive `sender.status_changed`. The sender, its\nconversations and its messages stay readable. Repeating the call is safe and\nanswers with the retired sender. Nothing changes in your Meta app: remove\nFlow's callback URL there, or point the number elsewhere, yourself.\n\nLive keys only. Shared sandbox senders belong to Flow and cannot be\ndisconnected (`403 permission` with a test key). iMessage lines and SMS\nnumbers, and WhatsApp numbers the Flow team manages for you, are\ndisconnected by Flow, not by API (`501 not_implemented`).\n\nTo use the bot or number again, connect it with `POST /v0/senders`; it\nbecomes a new sender.\n","href":"/api-reference/senders/disconnect-a-sender"},"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 ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from\\nFlow. For a bot, Flow removes its webhook (best effort) and deletes its\\nstored token; for a WhatsApp number, Flow deletes its stored token and app\\nsecret and stops taking its webhooks. Either way the sender is retired: its\\nstatus becomes \", _jsx(_components.code, {\n children: \"banned\"\n }), \", it no longer sends or receives, and messages still\\nqueued from it fail. You receive \", _jsx(_components.code, {\n children: \"sender.status_changed\"\n }), \". The sender, its\\nconversations and its messages stay readable. Repeating the call is safe and\\nanswers with the retired sender. Nothing changes in your Meta app: remove\\nFlow’s callback URL there, or point the number elsewhere, yourself.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Live keys only. Shared sandbox senders belong to Flow and cannot be\\ndisconnected (\", _jsx(_components.code, {\n children: \"403 permission\"\n }), \" with a test key). iMessage lines and SMS\\nnumbers, and WhatsApp numbers the Flow team manages for you, are\\ndisconnected by Flow, not by API (\", _jsx(_components.code, {\n children: \"501 not_implemented\"\n }), \").\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"To use the bot or number again, connect it with \", _jsx(_components.code, {\n children: \"POST /v0/senders\"\n }), \"; it\\nbecomes a new sender.\"]\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 DELETE /v0/senders/{sender_id}","title":"Disconnect a sender","description":"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from\nFlow. For a bot, Flow removes its webhook (best effort) and deletes its\nstored token; for a WhatsApp number, Flow deletes its stored token and app\nsecret and stops taking its webhooks. Either way the sender is retired: its\nstatus becomes `banned`, it no longer sends or receives, and messages still\nqueued from it fail. You receive `sender.status_changed`. The sender, its\nconversations and its messages stay readable. Repeating the call is safe and\nanswers with the retired sender. Nothing changes in your Meta app: remove\nFlow's callback URL there, or point the number elsewhere, yourself.\n\nLive keys only. Shared sandbox senders belong to Flow and cannot be\ndisconnected (`403 permission` with a test key). iMessage lines and SMS\nnumbers, and WhatsApp numbers the Flow team manages for you, are\ndisconnected by Flow, not by API (`501 not_implemented`).\n\nTo use the bot or number again, connect it with `POST /v0/senders`; it\nbecomes a new sender.\n","href":"/api-reference/senders/disconnect-a-sender"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/_mintlify/custom/flow-messaging/8b05b91b2b2979cc/default-host-redirect.js"],"openApiReferenceData":{"operation":{"operationId":"disconnectSender","tags":["Senders"],"summary":"Disconnect a sender","description":"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from\nFlow. For a bot, Flow removes its webhook (best effort) and deletes its\nstored token; for a WhatsApp number, Flow deletes its stored token and app\nsecret and stops taking its webhooks. Either way the sender is retired: its\nstatus becomes `banned`, it no longer sends or receives, and messages still\nqueued from it fail. You receive `sender.status_changed`. The sender, its\nconversations and its messages stay readable. Repeating the call is safe and\nanswers with the retired sender. Nothing changes in your Meta app: remove\nFlow's callback URL there, or point the number elsewhere, yourself.\n\nLive keys only. Shared sandbox senders belong to Flow and cannot be\ndisconnected (`403 permission` with a test key). iMessage lines and SMS\nnumbers, and WhatsApp numbers the Flow team manages for you, are\ndisconnected by Flow, not by API (`501 not_implemented`).\n\nTo use the bot or number again, connect it with `POST /v0/senders`; it\nbecomes a new sender.\n","responses":{"200":"f46f5cd2-7a0c-4e43-97a5-a6d3a4802677","400":"da8add56-614c-4411-a03f-18445fc7ce54","401":"3a9a8a2c-c554-4a68-ada7-5e7871f3d521","403":"dd05e3d1-bd75-4fb9-bc48-41eb129ccca1","404":"179bb0b1-d864-4ef4-9c85-67fa9d7dd2ea","429":"7a2b5df6-ced2-4ee7-b18e-5ed6687602cb","501":"d321e90e-440a-4baa-8905-efb378bc8e53","default":"945081ed-9cff-48d8-97a5-24039aacfdf9"},"method":"delete","type":"path","servers":["90a9657d-20c1-4182-87ad-a4d557fcda08"],"security":["59c5f960-0d19-49e7-944f-bfe75a0ffe7d"],"path":"/v0/senders/{sender_id}","baseUrlOptions":["https://api.flow.engineer"],"title":"Disconnect a sender","codeSamples":[],"requestExampleLanguages":["bash","javascript","python","go"],"requiredOnlyExamples":true,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"a7db449b-43fb-41ab-bac1-9686df58e903":{"name":"sender_id","in":"path","required":true,"description":"The sender's ID.","schema":{"type":"string","description":"The sender's ID.\nA sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"isRequired":true,"uniqueKey":"","typeLabel":"string"}},"7bc7ddd4-a252-4892-87b1-5d74c54a7ec5":{"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>"}}},"responses":{"f46f5cd2-7a0c-4e43-97a5-a6d3a4802677":{"description":"The sender is disconnected; it is returned with status `banned`.","content":{"application/json":{"schema":{"type":"object","description":"What your agent talks from: a Telegram bot, a WhatsApp number, an iMessage\nline or a US SMS number. `shared` senders are Flow's sandbox, used by many apps in test mode;\n`dedicated` senders are yours alone; `simulated` senders exist only in test\nmode, for simulated conversations. Each sender has its own limits and warm-up\nstate.\n","required":["id","channel","kind","livemode","status","address","limits","created_at"],"properties":{"id":{"type":"string","description":"A sender ID, `snd_` and a ULID.","pattern":"^snd_[0-9A-HJKMNP-TV-Z]{26}$","examples":["snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T"],"isRequired":true,"uniqueKey":"id","typeLabel":"string"},"channel":{"type":"string","description":"A messaging channel. `sms` is US SMS and MMS (in pilot), from dedicated numbers only.","enum":["telegram","whatsapp","imessage","sms"],"isRequired":true,"uniqueKey":"channel","typeLabel":"enum\u003cstring>"},"kind":{"type":"string","description":"`shared` (the sandbox), `dedicated` (yours) or `simulated` (test mode only:\nyour app's stand-in for a channel, used by simulated conversations from\n`POST /v0/test/conversations`; it never touches a network).\n","enum":["shared","dedicated","simulated"],"isRequired":true,"uniqueKey":"kind","typeLabel":"enum\u003cstring>"},"livemode":{"type":"boolean","description":"`false` for sandbox and simulated senders, `true` for dedicated senders used in live mode.","isRequired":true,"uniqueKey":"livemode","typeLabel":"boolean"},"status":{"type":"string","description":"- `pending`: requested, being provisioned.\n- `active`: sending normally.\n- `warming_up`: active, with a new-contact budget that grows day by day.\n- `throttled`: the gate slowed it after an abuse signal; it recovers by itself.\n- `flagged`: the channel or Flow flagged it; starts are paused. A Telegram\n bot is also `flagged` when Telegram rejects its token (revoked in\n @BotFather): it then sends nothing, new sends answer `403 permission`, and\n queued messages wait until you connect the bot again with its new token\n (`POST /v0/senders`). They wait at most 72 hours after Flow accepted\n them; older ones fail with `outside_window` (`channel_code`\n `queued_too_long`) in `message.failed` instead of going out late.\n- `banned`: it cannot send or receive: the channel banned it, you\n disconnected it (`DELETE /v0/senders/{sender_id}`), or its bot or line was\n connected to another app.\n","enum":["pending","active","warming_up","throttled","flagged","banned"],"isRequired":true,"uniqueKey":"status","typeLabel":"enum\u003cstring>"},"address":{"type":"object","description":"How contacts reach the sender. Which fields are set depends on the channel.","properties":{"phone":{"type":"string","description":"WhatsApp, iMessage and SMS. E.164 phone number.","uniqueKey":"address.phone","typeLabel":"string"},"username":{"type":"string","description":"Telegram. The bot's username, without `@`.","uniqueKey":"address.username","typeLabel":"string"},"handle":{"type":"string","description":"iMessage. The line's handle (phone number or email address).","uniqueKey":"address.handle","typeLabel":"string"},"link":{"type":"string","format":"uri","description":"A link that opens a chat with the sender: `https://t.me/...` for a Telegram\nbot, `https://wa.me/...` for a WhatsApp number. For an iMessage line it is\nthe line's opt-in link, which opens Messages with the line and a prefilled\ntext the person sends to start the conversation; it is set only when the\nline has one configured.\n","uniqueKey":"address.link","typeLabel":"string\u003curi>"}},"isRequired":true,"uniqueKey":"address","typeLabel":"object"},"limits":{"type":"object","description":"The sender's current budget for starting conversations, and how fast it sends.","required":["new_contacts_per_day","new_contacts_per_hour"],"properties":{"new_contacts_per_day":{"type":"integer","description":"New conversations the sender may start per day today (grows during warm-up).","isRequired":true,"uniqueKey":"limits.new_contacts_per_day","typeLabel":"integer"},"new_contacts_per_hour":{"type":"integer","description":"New conversations the sender may start per hour.","isRequired":true,"uniqueKey":"limits.new_contacts_per_hour","typeLabel":"integer"},"messages_per_second":{"type":"number","description":"The sender's pacing: how many messages a second it takes on average,\nreplies included, with short bursts allowed above it. A send past it\nanswers `429 rate_limited` with `retry_after`. A shared sandbox\nsender's pacing is shared by every app that uses it. Absent for\nsimulated senders, which are not paced.\n","examples":[1],"uniqueKey":"limits.messages_per_second","typeLabel":"number"},"whatsapp_tier":{"type":"string","description":"WhatsApp only. Meta's messaging tier for the number.","uniqueKey":"limits.whatsapp_tier","typeLabel":"string"}},"isRequired":true,"uniqueKey":"limits","typeLabel":"object"},"created_at":{"type":"string","format":"date-time","description":"When the sender was created.","isRequired":true,"uniqueKey":"created_at","typeLabel":"string\u003cdate-time>"},"display_name":{"type":"string","description":"The name contacts see, where the channel shows one.","uniqueKey":"display_name","typeLabel":"string"},"throttled_until":{"type":"string","format":"date-time","description":"With status `throttled`, when starts are allowed again. Recovery is automatic.","uniqueKey":"throttled_until","typeLabel":"string\u003cdate-time>"},"quality_rating":{"type":"string","description":"WhatsApp only. Meta's quality rating for the number.","enum":["green","yellow","red","unknown"],"uniqueKey":"quality_rating","typeLabel":"enum\u003cstring>"},"sms":{"type":"object","readOnly":true,"description":"SMS senders only: how the number is registered with US carriers and what it\ncan do. An SMS number stays `pending` until its registration is approved\n(carriers block traffic from unregistered numbers).\n","required":["number_type","registration_status","two_way","mms"],"properties":{"number_type":{"type":"string","description":"`10dlc` (a local 10-digit number, registered as a brand and campaign) or `toll_free` (a verified toll-free number).","enum":["10dlc","toll_free"],"isRequired":true,"uniqueKey":"sms.number_type","typeLabel":"enum\u003cstring>"},"registration_status":{"type":"string","description":"The number's carrier registration (the 10DLC campaign, or toll-free\nverification): `pending` (submitted, not approved yet; the sender is\n`pending` and sends nothing), `approved`, or `rejected` (the sender is\n`flagged`; the Flow team resubmits).\n","enum":["pending","approved","rejected"],"isRequired":true,"uniqueKey":"sms.registration_status","typeLabel":"enum\u003cstring>"},"two_way":{"type":"boolean","description":"Whether the number receives texts. Always `true` for senders Flow connects today.","isRequired":true,"uniqueKey":"sms.two_way","typeLabel":"boolean"},"mms":{"type":"boolean","description":"Whether the number sends and receives MMS (images, audio and video). Without it, a basic message with `media` answers `422 unsupported_content` with `param` `media` and `channel_code` `no_mms`.","isRequired":true,"uniqueKey":"sms.mms","typeLabel":"boolean"},"quiet_hours":{"type":"object","description":"The hours, in the contact's local time zone (worked out from their area\ncode; when it is not known, every US time zone must be outside the\nhours), in which the sender does not message contacts who have not texted\nit in the last hour. Absent when the sender has no quiet hours. A send\ninside them answers `409 outside_window` with `channel_code` `quiet_hours`\nand `retry_after`; a message that waited in the queue into them is held\nuntil they end. Replies to a contact who texted within the hour always\ngo.\n","required":["start","end"],"properties":{"start":{"type":"string","description":"When the quiet hours begin, `HH:MM` on a 24-hour clock.","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","examples":["21:00"],"isRequired":true,"uniqueKey":"sms.quiet_hours.start","typeLabel":"string"},"end":{"type":"string","description":"When they end, `HH:MM` on a 24-hour clock (earlier than `start` when they span midnight).","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","examples":["08:00"],"isRequired":true,"uniqueKey":"sms.quiet_hours.end","typeLabel":"string"}},"uniqueKey":"sms.quiet_hours","typeLabel":"object"}},"uniqueKey":"sms","typeLabel":"object"},"imessage":{"type":"object","readOnly":true,"description":"iMessage senders only: what the line can do beyond replying in iMessage.\nSet by the Flow team (ask them to change it); absent on other channels.\n","required":["fallback","can_initiate"],"properties":{"fallback":{"type":"boolean","description":"Whether messages to a contact who cannot get iMessage go by SMS or RCS\ninstead. The network is chosen for each message when it is sent, never\nby your app; the message's `network` says which one carried it.\nIncluded on Flow's shared lines; on a dedicated line, an add-on\narranged with the Flow team. Off, a message to a contact who is not on\niMessage fails (`message.failed`). A message that goes by SMS or RCS\nshows no `imessage.styles`, `imessage.subject` or effect, and edits\nand unsends of it answer `422 unsupported_content` with\n`channel_code` `not_on_sms` (see `Message.network`).\n","isRequired":true,"uniqueKey":"imessage.fallback","typeLabel":"boolean"},"can_initiate":{"type":"boolean","description":"Whether the line may write first: start a conversation with\n`POST /v0/messages` with a contact who has not messaged it. Off (the\ndefault), the line only replies and a start answers `403 permission`.\nWriting first is available on request from the Flow team, on dedicated\nlines only (always `false` on shared lines); a line that starts\nconversations spends its new-contact budget (`limits`), which grows\nduring warm-up.\n","isRequired":true,"uniqueKey":"imessage.can_initiate","typeLabel":"boolean"},"call_forwarding":{"type":"object","description":"Dedicated lines only: where phone calls to the line's number are\nforwarded, set up with the Flow team. Forwarded calls send no event.\nFaceTime calls are not forwarded; they arrive as `call.received`. Absent\nwhen calls are not forwarded (always on shared lines).\n","required":["phone"],"properties":{"phone":{"type":"string","description":"The E.164 number calls are forwarded to.","pattern":"^\\+[1-9][0-9]{6,14}$","examples":["+15555550123"],"isRequired":true,"uniqueKey":"imessage.call_forwarding.phone","typeLabel":"string"}},"uniqueKey":"imessage.call_forwarding","typeLabel":"object"}},"uniqueKey":"imessage","typeLabel":"object"},"setup":{"type":"object","readOnly":true,"description":"Only in the answer to `POST /v0/senders` that connected a WhatsApp number:\nwhat you still set in your own Meta app, which Flow cannot set for you.\nFlow already points the number's webhooks at `callback_url` (Meta's\nphone-number-level override); entering the same URL in your app makes its\nfield subscriptions apply. The verify token is shown only in this answer\n(connecting the number again shows it again); keep it like a password.\n","required":["callback_url","verify_token","webhook_fields","steps"],"properties":{"callback_url":{"type":"string","format":"uri","description":"The callback URL to enter in your Meta app (App Dashboard > WhatsApp > Configuration > Webhook).","examples":["https://api.flow.engineer/ingress/whatsapp/snd_01J9ZK3N5B6VQ1M2X4C7R8T9WA"],"isRequired":true,"uniqueKey":"setup.callback_url","typeLabel":"string\u003curi>"},"verify_token":{"type":"string","description":"The verify token to enter with the callback URL.","isRequired":true,"uniqueKey":"setup.verify_token","typeLabel":"string"},"webhook_fields":{"type":"array","description":"The webhook fields to subscribe in the same place.","items":{"type":"string","uniqueKey":"setup.webhook_fields.items.[INDEX]","typeLabel":"string"},"examples":[["messages","message_template_status_update","phone_number_quality_update","account_update","business_capability_update","template_category_update","account_alerts"]],"isRequired":true,"uniqueKey":"setup.webhook_fields","typeLabel":"string[]"},"steps":{"type":"array","description":"The steps in your Meta app, in order, as plain sentences to show a person.","items":{"type":"string","uniqueKey":"setup.steps.items.[INDEX]","typeLabel":"string"},"isRequired":true,"uniqueKey":"setup.steps","typeLabel":"string[]"}},"uniqueKey":"setup","typeLabel":"object"},"join_code":{"type":"string","description":"Shared senders only. The whole message a contact sends to this sender to join your app: `Hi `, the app's name (`there` when it has none), then the app's `sandbox_join_code` (from `GET /v0/app`) in brackets after `ref`, for example `Hi Sandbox app (ref brave-otter-40718263)`. Show it to testers as is; a link that fills it in (wa.me, sms:) carries it URL-encoded. Any message of at most 160 characters that ends with `(ref \u003ccode>)` joins, so a tester may change the words before the brackets.\n","examples":["Hi Sandbox app (ref brave-otter-40718263)"],"uniqueKey":"join_code","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"id":"snd_01JB8Z4Q3V6W0R2N7C5H1M9K4T","channel":"telegram","kind":"shared","livemode":true,"status":"pending","address":{"phone":"\u003cstring>","username":"\u003cstring>","handle":"\u003cstring>","link":"\u003cstring>"},"limits":{"new_contacts_per_day":123,"new_contacts_per_hour":123,"messages_per_second":1,"whatsapp_tier":"\u003cstring>"},"created_at":"2023-11-07T05:31:56Z","display_name":"\u003cstring>","throttled_until":"2023-11-07T05:31:56Z","quality_rating":"green","sms":{"number_type":"10dlc","registration_status":"pending","two_way":true,"mms":true,"quiet_hours":{"start":"21:00","end":"08:00"}},"imessage":{"fallback":true,"can_initiate":true,"call_forwarding":{"phone":"+15555550123"}},"setup":{"callback_url":"https://api.flow.engineer/ingress/whatsapp/snd_01J9ZK3N5B6VQ1M2X4C7R8T9WA","verify_token":"\u003cstring>","webhook_fields":["messages","message_template_status_update","phone_number_quality_update","account_update","business_capability_update","template_category_update","account_alerts"],"steps":["\u003cstring>"]},"join_code":"Hi Sandbox app (ref brave-otter-40718263)"}}},"exampleType":"generated"}},"exampleType":"generated"},"da8add56-614c-4411-a03f-18445fc7ce54":{"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"},"3a9a8a2c-c554-4a68-ada7-5e7871f3d521":{"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"},"dd05e3d1-bd75-4fb9-bc48-41eb129ccca1":{"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"},"179bb0b1-d864-4ef4-9c85-67fa9d7dd2ea":{"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"},"7a2b5df6-ced2-4ee7-b18e-5ed6687602cb":{"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"},"d321e90e-440a-4baa-8905-efb378bc8e53":{"description":"Not available through the API during the beta (`not_implemented`), for\nexample a sender of a channel the Flow team connects and disconnects for\nyou. The `hint` says what to do 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"},"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"},"945081ed-9cff-48d8-97a5-24039aacfdf9":{"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":"Disconnect a sender - Flow","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-24T16:17:30.738Z","originalFileLocation":"api-reference/senders/disconnect-a-sender.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=\"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from Flow. For a bot, Flow removes its webhook (best effort) and deletes its stored token; for a WhatsApp number, Flow deletes its stored token and app secret and stops taking its webhooks. Either way the sender is retired: its status becomes banned, it no longer sends or receives, and messages still queued from it fail. You receive sender.status_changed. The sender, its conversations and its messages stay readable. Repeating the call is safe and answers with the retired sender. Nothing changes in your Meta app: remove Flow\u0026#x27;s callback URL there, or point the number elsewhere, yourself. Live keys only. Shared sandbox senders belong to Flow and cannot be disconnected (403 permission with a test key). iMessage lines and SMS numbers, and WhatsApp numbers the Flow team manages for you, are disconnected by Flow, not by API (501 not_implemented). To use the bot or number again, connect it with POST /v0/senders; it becomes a new sender.\">\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=\"Disconnect a sender - Flow\">\u003cmeta data-mint-head property=\"og:description\" content=\"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from Flow. For a bot, Flow removes its webhook (best effort) and deletes its stored token; for a WhatsApp number, Flow deletes its stored token and app secret and stops taking its webhooks. Either way the sender is retired: its status becomes banned, it no longer sends or receives, and messages still queued from it fail. You receive sender.status_changed. The sender, its conversations and its messages stay readable. Repeating the call is safe and answers with the retired sender. Nothing changes in your Meta app: remove Flow\u0026#x27;s callback URL there, or point the number elsewhere, yourself. Live keys only. Shared sandbox senders belong to Flow and cannot be disconnected (403 permission with a test key). iMessage lines and SMS numbers, and WhatsApp numbers the Flow team manages for you, are disconnected by Flow, not by API (501 not_implemented). To use the bot or number again, connect it with POST /v0/senders; it becomes a new sender.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Flow\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender\">\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=Senders+and+templates\u0026amp;title=Disconnect+a+sender\u0026amp;description=Disconnects+one+of+your+dedicated+Telegram+bots+or+WhatsApp+numbers+from%0AFlow.+For+a+bot%2C+Flow+removes+its+webhook+%28best+effort%29+and+deletes+its%0Astored+token%3B+f\u0026amp;theme=052dec2df14a3094abf38032\u0026amp;signature=0bbab6b4d4ce6c87226e6c02d130d250216f2a8f438c10c17dd0c45479569ff8\">\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=\"Disconnect a sender - Flow\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from Flow. For a bot, Flow removes its webhook (best effort) and deletes its stored token; for a WhatsApp number, Flow deletes its stored token and app secret and stops taking its webhooks. Either way the sender is retired: its status becomes banned, it no longer sends or receives, and messages still queued from it fail. You receive sender.status_changed. The sender, its conversations and its messages stay readable. Repeating the call is safe and answers with the retired sender. Nothing changes in your Meta app: remove Flow\u0026#x27;s callback URL there, or point the number elsewhere, yourself. Live keys only. Shared sandbox senders belong to Flow and cannot be disconnected (403 permission with a test key). iMessage lines and SMS numbers, and WhatsApp numbers the Flow team manages for you, are disconnected by Flow, not by API (501 not_implemented). To use the bot or number again, connect it with POST /v0/senders; it becomes a new sender.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://flow-messaging.mintlify.app/_mintlify/api/og/v2?division=Senders+and+templates\u0026amp;title=Disconnect+a+sender\u0026amp;description=Disconnects+one+of+your+dedicated+Telegram+bots+or+WhatsApp+numbers+from%0AFlow.+For+a+bot%2C+Flow+removes+its+webhook+%28best+effort%29+and+deletes+its%0Astored+token%3B+f\u0026amp;theme=052dec2df14a3094abf38032\u0026amp;signature=0bbab6b4d4ce6c87226e6c02d130d250216f2a8f438c10c17dd0c45479569ff8\">\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/senders/disconnect-a-sender\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api-reference/senders/disconnect-a-sender.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/senders/disconnect-a-sender#webpage\",\"url\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender\",\"name\":\"Disconnect a sender\",\"description\":\"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from Flow. For a bot, Flow removes its webhook (best effort) and deletes its stored token; for a WhatsApp number, Flow deletes its stored token and app secret and stops taking its webhooks. Either way the sender is retired: its status becomes banned, it no longer sends or receives, and messages still queued from it fail. You receive sender.status_changed. The sender, its conversations and its messages stay readable. Repeating the call is safe and answers with the retired sender. Nothing changes in your Meta app: remove Flow's callback URL there, or point the number elsewhere, yourself. Live keys only. Shared sandbox senders belong to Flow and cannot be disconnected (403 permission with a test key). iMessage lines and SMS numbers, and WhatsApp numbers the Flow team manages for you, are disconnected by Flow, not by API (501 not_implemented). To use the bot or number again, connect it with POST /v0/senders; it becomes a new sender.\",\"dateModified\":\"2026-10-24T16:17:30.738Z\",\"isPartOf\":{\"@id\":\"https://docs.flow.engineer#website\"},\"breadcrumb\":{\"@id\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender#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\":\"Senders and templates\",\"item\":\"https://docs.flow.engineer/api-reference/senders/list-senders\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Disconnect a sender\",\"item\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender#apireference\",\"headline\":\"Disconnect a sender\",\"name\":\"Disconnect a sender\",\"description\":\"Disconnects one of your dedicated Telegram bots or WhatsApp numbers from Flow. For a bot, Flow removes its webhook (best effort) and deletes its stored token; for a WhatsApp number, Flow deletes its stored token and app secret and stops taking its webhooks. Either way the sender is retired: its status becomes banned, it no longer sends or receives, and messages still queued from it fail. You receive sender.status_changed. The sender, its conversations and its messages stay readable. Repeating the call is safe and answers with the retired sender. Nothing changes in your Meta app: remove Flow's callback URL there, or point the number elsewhere, yourself. Live keys only. Shared sandbox senders belong to Flow and cannot be disconnected (403 permission with a test key). iMessage lines and SMS numbers, and WhatsApp numbers the Flow team manages for you, are disconnected by Flow, not by API (501 not_implemented). To use the bot or number again, connect it with POST /v0/senders; it becomes a new sender.\",\"url\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender\",\"mainEntityOfPage\":{\"@id\":\"https://docs.flow.engineer/api-reference/senders/disconnect-a-sender#webpage\"},\"dateModified\":\"2026-10-24T16:17:30.738Z\",\"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","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","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","description":"Deletes the template at Meta and here. Messages already sent with it are\nunaffected. Templates of a shared sandbox sender belong to Flow and cannot\nbe deleted (`403 permission`).\n","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","description":"Lists the contacts your app has talked with in this mode, newest first.","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":"Disconnect a sender - 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"]}