> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flow.engineer/llms.txt
> Use this file to discover all available pages before exploring further.

# WhatsApp

> Connect your number, send replies and handle templates outside the reply window.

Connect your own WhatsApp number with a live key, receive messages and deliver your agent's
answer through the Unified API. Use buttons in the reply window and approved templates after it.

> [!NOTE]
>
> Connect a number in your WhatsApp Business Account with `POST /v0/senders` or the
> dashboard's [Senders page](https://api.flow.engineer/admin/senders?mode=live).
> The shared WhatsApp sandbox is not open; test on Telegram first with the same handler.

```ts TypeScript theme={null}
// app/api/whatsapp/route.ts (Next.js). npm install @flow-engineer/messaging ai @ai-sdk/openai
import { FlowMessaging, contentText } from "@flow-engineer/messaging";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";

const flow = new FlowMessaging();

export const POST = flow.webhooks.handler({
  onEvent: async (event) => {
    if (event.type !== "message.received") return;
    const question = contentText(event.data.message.content); // text, caption or a tapped button's label
    // Answer after the webhook returns: reply() keeps typing on and sends bubbles as they are ready.
    void event.conversation.reply(
      streamText({ model: openai("gpt-4.1-mini"), system: "You are the assistant for Asha's Bakery.", prompt: question }),
      { idempotencyKey: event.id },
    );
  },
});
```

> [!NOTE]
>
> On serverless platforms that stop work when the response is sent, run the reply with your platform's background helper (for example `after()` in Next.js or `waitUntil()`), or answer in the webhook response itself as shown below.

## 1. Build it on Telegram today

There is no WhatsApp sandbox yet. Run the same code on the Telegram sandbox bot:

1. Get a test key, with no account: `curl -X POST https://api.flow.engineer/v0/sandbox/keys` (or `npx @flow-engineer/messaging init`). Set its `key` as `FLOW_MESSAGING_KEY`. See [Keys and sign-in](https://docs.flow.engineer/unified-messaging-api/get-a-key.md).
2. Join the Telegram sandbox from your phone with the bot's `address.link` (see [Build a Telegram agent](https://docs.flow.engineer/unified-messaging-api/guides/telegram-agent.md)).
3. Register your webhook, or on your laptop read events from the live stream (`GET /v0/stream`, see [Local development](https://docs.flow.engineer/unified-messaging-api/guides/local-development.md)), and send a message.

When the WhatsApp sandbox opens, the sandbox allowance will cover it.

## 2. Answer fast: reply in the webhook response

For short answers, skip the extra API call and return the reply from the webhook handler:

```ts TypeScript theme={null}
export const POST = flow.webhooks.handler({
  onEvent: async (event) => {
    if (event.type !== "message.received") return;
    return await answer(contentText(event.data.message.content)); // a string, a kind object, or a list of up to 11
  },
});
```

```json HTTP response body theme={null}
{ "reply": { "kind": "basic", "text": "Yes, we deliver to 560103. Delivery takes about 40 minutes." } }
```

Answer within 10 seconds; for anything slower, answer `200 {}` at once and send with the kinds' endpoints, such as `POST /v0/conversations/{conversation_id}/basic`.

## 3. Voice notes

WhatsApp users send a lot of voice notes. Each one arrives as a `voice` message with the audio file (`url`, `file_id`):

```json theme={null}
{ "kind": "voice", "url": "https://api.flow.engineer/v0/files/file_01JB8ZC3K5M7P9R1T3V5X7Z9B1", "duration_seconds": 4.2 }
```

Flow does not transcribe voice notes yet, so fetch the audio and transcribe it yourself if your agent needs the words. To send a voice note back, use [`POST /v0/conversations/{conversation_id}/voice`](https://docs.flow.engineer/api-reference/messages/send-a-voice-note) with an audio `url` or `file_id`.

## 4. Buttons and lists

WhatsApp shows up to 3 reply buttons ([`buttons`](https://docs.flow.engineer/api-reference/messages/send-text-with-buttons)). For 4 to 10 choices, send a [`list`](https://docs.flow.engineer/api-reference/messages/send-a-list-to-pick-one-option-from): more than 3 buttons answer `422 unsupported_content` with `param` `buttons`, and Flow does not turn them into a list for you.

```ts TypeScript theme={null}
import { buttons } from "@flow-engineer/messaging";

await event.conversation.send(buttons("How would you like to pay?", [
  { id: "upi", label: "UPI" },
  { id: "card", label: "Card" },
  { id: "cod", label: "Cash on delivery" },
]));
```

A tap on a button or a list row arrives as `message.received` with a `button_reply` message: `{ "kind": "button_reply", "button_id": "upi", "label": "UPI" }`. Labels are at most 20 characters.

## 5. The 24-hour window and templates

WhatsApp allows free-form messages only within **24 hours of the person's last message**. After that, and to message someone first, you must send an approved **template**.

* Every event carries `conversation.window_open_until`.
* A free-form send outside the window fails with `409` [`outside_window`](https://docs.flow.engineer/unified-messaging-api/errors/outside_window).
* Subscribe to `conversation.window_closing` to get a warning 1 hour before it closes.

```ts TypeScript theme={null}
import { template } from "@flow-engineer/messaging";

// Follow up two days later: only a template may go.
await flow.conversation(conversationId).send(
  template("tpl_01JB8ZC3K5M7P9R1T3V5X7Z9B1", "en", { body: ["Asha", "order 1042"] }),
);
```

Templates are created on your dedicated WhatsApp number with `POST /v0/templates`, with a realistic sample for each placeholder (`examples`), and reviewed by WhatsApp; you receive `template.status_changed` when one is approved, rejected or paused. See [Going live](https://docs.flow.engineer/unified-messaging-api/guides/going-live.md#whatsapp-templates).

## 6. What WhatsApp supports

| Kind | WhatsApp |
| - | - |
| Text (`basic`) | yes, sent as written; WhatsApp's app shows its own `*bold*` and `_italic_` |
| Images, video, documents, audio | yes |
| Voice notes | yes, both ways |
| Buttons | 1 to 3 reply buttons, or one URL button; a `list` for up to 10 rows |
| Reactions, read receipts | yes |
| Typing | within 24 hours of the person's last message, once they have written |
| Locations, contact cards, carousels | yes |
| Edit or unsend | no (`422 unsupported_content`) |
| Link previews | `link_preview` on a basic message (shown by default; `false` sends links as plain text) |

## 7. Going live on WhatsApp

Connect a number in your business's own WhatsApp Business Account yourself, with `POST /v0/senders` (`"channel": "whatsapp"`) and a live key, or on the dashboard's [Senders page](https://api.flow.engineer/admin/senders?mode=live): see [Going live](https://docs.flow.engineer/unified-messaging-api/guides/going-live.md#your-own-number) for the steps in Meta Business Manager and the `setup` to enter in your Meta app. The Flow team can also connect a number for you, either one Flow provides or one in your own account. With your own account, add a payment method in WhatsApp Manager: Meta bills its fees to your business directly. On a number Flow provides, Meta's per-message fees are passed through (see [Pricing](https://docs.flow.engineer/unified-messaging-api/pricing.md)). Once the number is connected it appears in `GET /v0/senders` with your live key, and your agent's code stays the same.

> [!WARNING]
>
> WhatsApp's business policy does not allow general-purpose AI assistants. Your agent must serve your business's own customers (support, orders, bookings, updates). Agents that only reply to people who wrote first, about your business, are the safe pattern.

## Related

* [The send gate](https://docs.flow.engineer/unified-messaging-api/concepts/send-gate.md): windows, new-contact limits and quality.
* [Streaming replies](https://docs.flow.engineer/unified-messaging-api/concepts/streaming-replies.md) and [Content types](https://docs.flow.engineer/unified-messaging-api/concepts/content-types.md).
* Frameworks: [Vercel AI SDK](https://docs.flow.engineer/unified-messaging-api/frameworks/vercel-ai-sdk.md), [OpenAI Agents SDK](https://docs.flow.engineer/unified-messaging-api/frameworks/openai-agents-sdk.md), [LangChain](https://docs.flow.engineer/unified-messaging-api/frameworks/langchain.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.