Skip to content

Ask the docs

Answers come only from these docs and are written by an AI model (Gemini), so check the linked pages. Your question is not kept. Do not include personal details or keys.

Go live

Going live · dedicated WhatsApp number for AI agent · WhatsApp business verification API · WhatsApp message templates API · iMessage dedicated line · go live WhatsApp API

Connect a dedicated sender, use a live key and check production delivery.

Going live means sending from a dedicated sender of your own with a live key; your agent’s code does not change. The examples below assume FLOW_MESSAGING_KEY holds your live key (fk_live_...).

curl
export TELEGRAM_BOT_TOKEN=... # the token from @BotFather; never commit it
curl https://api.flow.engineer/v0/senders \
-H "Authorization: Bearer $FLOW_MESSAGING_KEY" \
-H "Content-Type: application/json" \
-d "{\"channel\": \"telegram\", \"telegram_bot_token\": \"$TELEGRAM_BOT_TOKEN\"}"
ChannelHow you go live today
TelegramSelf-serve: connect your own bot with a live key (below).
iMessageFlow’s shared line works with a live key once your account has it (the free trial your first sign-in at flow.engineer starts opens it, and a paid plan keeps it). For a line of your own, ask the Flow team (Dedicated plan). Lines reply after the person writes first; writing first is available on request for dedicated lines.
WhatsAppSelf-serve: connect a number in your own WhatsApp Business Account with a live key (below), or in the dashboard. The Flow team can also connect one for you.

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.

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).

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.

Switch the key

Set FLOW_MESSAGING_KEY to the live key and deploy. Watch message.failed and sender.status_changed for the first days.

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:

  1. Create a Meta app of type Business with the WhatsApp product, and switch it to Live.
  2. 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).
  3. 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_messaging and whatsapp_business_management.

Then connect the number. Keep the token and the app secret (App settings > Basic) in environment variables, never in code or a chat:

curl
export WHATSAPP_ACCESS_TOKEN=... # the system user token; never commit it
export WHATSAPP_APP_SECRET=... # your Meta app's App secret
curl https://api.flow.engineer/v0/senders \
-H "Authorization: Bearer $FLOW_MESSAGING_KEY" \
-H "Content-Type: application/json" \
-d "{\"channel\": \"whatsapp\", \"whatsapp_phone_number_id\": \"106540352242922\", \"whatsapp_business_account_id\": \"102290129340398\", \"whatsapp_access_token\": \"$WHATSAPP_ACCESS_TOKEN\", \"whatsapp_app_secret\": \"$WHATSAPP_APP_SECRET\"}"

Use your number’s phone number ID (WhatsApp Manager, or App Dashboard > WhatsApp > API Setup), not the phone number itself. Add whatsapp_registration_pin (six digits) only when the number is not registered for the Cloud API yet, and display_name if you like.

  • Answer: 200 with the sender active and, only in this answer, setup: enter its callback_url and verify_token in your Meta app (App Dashboard > WhatsApp > Configuration) and subscribe the webhook_fields there, following its steps. 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 permission with channel_code whatsapp_number_managed, and 501 not_implemented on DELETE).
  • 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 in limits.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.

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
curl https://api.flow.engineer/v0/templates \
-H "Authorization: Bearer $FLOW_MESSAGING_KEY" \
-H "Content-Type: application/json" \
-d '{
"sender": "snd_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"name": "order_ready",
"language": "en",
"category": "utility",
"components": [
{ "type": "body", "text": "Hi {{1}}, your {{2}} is ready for pickup.", "examples": ["Asha", "cake"] },
{ "type": "buttons", "buttons": [
{ "type": "url", "text": "See order", "url": "https://shop.example.com/orders/{{1}}", "example": "A-1042" }
] }
]
}'

The answer is 201 with the template, pending until WhatsApp reviews it, its components as you sent them:

{
"id": "tpl_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"sender": "snd_01JB8ZC3K5M7P9R1T3V5X7Z9B1",
"name": "order_ready",
"language": "en",
"category": "utility",
"status": "pending",
"components": [
{ "type": "body", "text": "Hi {{1}}, your {{2}} is ready for pickup.", "examples": ["Asha", "cake"] },
{ "type": "buttons", "buttons": [
{ "type": "url", "text": "See order", "url": "https://shop.example.com/orders/{{1}}", "example": "A-1042" }
] }
],
"created_at": "2026-10-24T09:30:00Z"
}
  • Always give samples. WhatsApp reviews a template with them. Put examples on the body and on a text header, one value per placeholder in order ({{1}} first), and example on a url button 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 gets 400 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.
  • category is utility (updates about something the person asked for), marketing or authentication; it sets WhatsApp’s fee.
  • You receive template.status_changed when WhatsApp approves, rejects (with rejection_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 with POST /v0/messages and "kind": "template"), with values for its placeholders, the url button’s by its position (from 0):
{ "template_id": "tpl_01JB8ZC3K5M7P9R1T3V5X7Z9B1", "language": "en", "params": { "body": ["Asha", "cake"], "buttons": [{ "index": 0, "value": "A-1042" }] } }
  • 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=imessage with 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 group conversations.
  • Get people to write: the sender’s address.link is 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.

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 flagged until you do. Messages queued while it is flagged wait at most 72 hours, then fail with outside_window (channel_code queued_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.
  • Handle outside_window, new_contact_limit and sender_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.