FLOW_MESSAGING_KEY holds your live key (fk_live_...).
curl
Checklist
1
Get a live key
Sign in to the dashboard with a Flow account, switch to Live, and make an
fk_live_... key on the Keys page (test keys take one call, see Keys and sign-in). Keep it on your server only, in its own variable (for example FLOW_MESSAGING_LIVE_KEY) so it does not replace your test key. Your own Telegram bot and your own WhatsApp number are self-serve; iMessage lines are arranged with the Flow team.2
Get a dedicated sender
Telegram:
POST /v0/senders with your bot’s token; it is active at once. WhatsApp: POST /v0/senders with your number’s IDs, token and app secret (see WhatsApp); it is active at once. iMessage: the Flow team connects a line to your app, and it then appears in GET /v0/senders with your live key (POST /v0/senders with "channel": "imessage" answers 501 not_implemented with any key; build meanwhile on simulated conversations of that channel).3
Register your webhook with the live key
Webhook endpoints and their signing secrets belong to one mode: your test endpoint never receives live events.
POST /v0/webhook_endpoints again with the live key and store the new whsec_... secret where your live deployment reads it; the test endpoint keeps its own secret.4
Switch the key
Set
FLOW_MESSAGING_KEY to the live key and deploy. Watch message.failed and sender.status_changed for the first days.Your own number
Connect a number in your own WhatsApp Business Account, under your own Meta app, with a live key:POST /v0/senders, or the Senders page of the dashboard. The Flow team can also connect a number for you.
First, in Meta Business Manager:
- Create a Meta app of type Business with the WhatsApp product, and switch it to Live.
- Add the phone number to your WhatsApp Business Account, with an approved display name, and add a payment method in WhatsApp Manager (Meta bills its fees to you directly).
- Create a system user (Admin), assign it your WhatsApp Business Account (full control) and the app, and generate a token that never expires with
whatsapp_business_messagingandwhatsapp_business_management.
curl
whatsapp_registration_pin (six digits) only when the number is not registered for the Cloud API yet, and display_name if you like.
- Answer:
200with the senderactiveand, only in this answer,setup: enter itscallback_urlandverify_tokenin your Meta app (App Dashboard > WhatsApp > Configuration) and subscribe thewebhook_fieldsthere, following itssteps. Flow has already pointed this number’s webhooks at Flow (your other numbers keep theirs); the settings in your app make its field subscriptions apply. The verify token is shown only in this answer. - New token: send the number again the same way. It stays the same sender, with the same verify token.
- Disconnect:
DELETE /v0/senders/{sender_id}deletes the stored token and app secret and retires the sender. Nothing changes in your Meta app: remove Flow’s callback URL there yourself. - Numbers the Flow team connected are updated and disconnected by the Flow team (
403 permissionwithchannel_codewhatsapp_number_managed, and501 not_implementedonDELETE).
Numbers, quality and fees
- Numbers: a number in your business’s own WhatsApp Business Account, or a number Flow provides.
- Quality and tiers: the sender shows WhatsApp’s
quality_rating(green,yellow,red) and its messaging tier inlimits.whatsapp_tier. Replies to people who wrote first are not limited by the tier. - Fees: on a number Flow provides, WhatsApp’s own per-message fees (charged by Meta) are passed through. With your own WhatsApp Business Account, Meta bills its fees to your business directly, so add a payment method in WhatsApp Manager. See Pricing.
WhatsApp templates
A template is a message WhatsApp approved in advance. On WhatsApp you need one to message someone first, or to write more than 24 hours after their last message. Templates are created on your WhatsApp number, with a realistic sample for each placeholder:curl
201 with the template, pending until WhatsApp reviews it, its components as you sent them:
- Always give samples. WhatsApp reviews a template with them. Put
exampleson the body and on a text header, one value per placeholder in order ({{1}}first), andexampleon aurlbutton whose link ends in{{1}}: the end of the link, which Flow shows WhatsApp in place. Left out, Flow sends placeholder samples (x1,x2, …), which WhatsApp often rejects or moves to another category. - Sample limits: exactly one per placeholder; 1 to 60 characters in a header and 1 to 1024 in a body; no line breaks, tabs or more than four spaces in a row. The url sample has no spaces, and the link with it in place is at most 2000 characters.
- Placeholders are numbered
{{1}},{{2}}, … with none skipped. A header has at most one, a footer none, and a url button’s link only{{1}}, at its end. A template that breaks these rules or the sample limits gets400 invalid_request, and so do samples on a footer, a buttons part, a media header or text without placeholders. - Names use lowercase letters, digits and underscores. A name and language pair is unique per sender.
categoryisutility(updates about something the person asked for),marketingorauthentication; it sets WhatsApp’s fee.- You receive
template.status_changedwhen WhatsApp approves, rejects (withrejection_reason) or pauses it. - In the dashboard, open your WhatsApp number on the Senders page, then Templates: its New template form always sends its sample values.
- Send it with
POST /v0/conversations/{conversation_id}/template(or start a conversation withPOST /v0/messagesand"kind": "template"), with values for its placeholders, the url button’s by its position (from 0):
iMessage: a dedicated line
- Get one: ask the Flow team for a line on the Dedicated plan (Pricing). They connect it to your app; it is listed in
GET /v0/senders?channel=imessagewith your live key. Flow’s shared line needs no setup: once your account has it (the free trial, kept on a paid plan), a live key sees it too, with your app’s live join message. - The person writes first: starting a conversation with a new contact is refused with
403 permission, unless writing first is switched on for the line (imessage.can_initiate). Writing first is available on request for dedicated lines, within a warm-up. - Add-ons on a dedicated line, arranged with the Flow team: SMS and RCS from the same number (for contacts who cannot get iMessage), and forwarding of phone calls. Group chats people add the line to reach your app as
groupconversations. - Get people to write: the sender’s
address.linkis the line’s opt-in link (when it has one): it opens Messages with the line and a prefilled text. Publish it on your site, receipts or QR codes. See Build an iMessage agent.
Telegram: your own bot
Create a bot with @BotFather and send its token:POST /v0/senders with channel: "telegram" and telegram_bot_token. It is connected and active at once. See Build a Telegram agent.
- New token: after revoking a token in @BotFather, send the new one the same way. The bot stays the same sender; one Telegram rejected meanwhile is
flaggeduntil you do. Messages queued while it is flagged wait at most 72 hours, then fail withoutside_window(channel_codequeued_too_long). - Disconnect:
DELETE /v0/senders/{sender_id}removes the bot’s webhook and token and retires the sender. - One app per bot: connecting a bot to another app moves it there and retires the old sender.
Before you launch
- Handle
outside_window,new_contact_limitandsender_throttled(see Errors). Know the sending limits and abuse signals: the same first message to many new contacts throttles a sender for 24 hours. - Deduplicate webhook deliveries on the event
id, and use event IDs as idempotency keys. - Subscribe your webhook only to the event types you use.
- Message content and media are kept for your plan’s retention period (30 days by default); store anything you need longer yourself.