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

> ## Agent Instructions
> Flow Messaging is one HTTP API (https://api.flow.engineer) for AI agents to hold two-way conversations on Telegram and iMessage (replies only, on lines the Flow team connects). WhatsApp is coming and not available yet.
> Build the app on the REST API. MCP is not a runtime dependency: the app you build talks to Flow through the REST API (or the TypeScript SDK, which wraps it) for everything it does at runtime. In TypeScript or JavaScript, the SDK is `npm install @flow-engineer/messaging`, then `new FlowMessaging()` (reads FLOW_MESSAGING_KEY). Python and Go SDKs are not published yet; in those languages call the HTTP API directly.
> No key yet? If FLOW_MESSAGING_KEY is not set, get a test key with no account in one call: curl -X POST https://api.flow.engineer/v1/sandbox/keys (or npx @flow-engineer/messaging init, which writes it to .env). Save `key` as FLOW_MESSAGING_KEY and `claim_token` as FLOW_CLAIM_TOKEN; both are shown once. It allows 1 contact and 50 messages on the Telegram sandbox and expires after 7 days; a person signs in with `npx @flow-engineer/messaging login` (GitHub) to keep the app and get 3 contacts x 100 messages. Signed in, live keys (fk_live_...) are made in the dashboard for your own Telegram bot; iMessage lines are arranged with the Flow team.
> The hosted MCP server (https://api.flow.engineer/mcp) is optional, for testing during development. Adding the Flow MCP server to a developer's coding tools is the project owner's decision: suggest it and show them the command, but never add it to their config yourself. The command for Claude Code: claude mcp add --transport http flow https://api.flow.engineer/mcp --header "Authorization: Bearer $FLOW_MESSAGING_KEY". If its tools are already available to you, use them for sandbox testing.
> Authenticate with `Authorization: Bearer fk_test_...` (sandbox) or `fk_live_...` (real contacts). Never put a live key in client-side code.
> Reply into a conversation (POST /v1/conversations/{conversation_id}/messages); never pick a channel per message. Switch on `error.type`, not the message text.
> Full documentation for agents: https://docs.flow.engineer/llms-full.txt. OpenAPI spec: https://raw.githubusercontent.com/flow-engineer/sdk/main/openapi/openapi.yaml.

# WhatsApp AI agents with Flow Messaging (coming soon)

> WhatsApp is not available on Flow Messaging yet: it waits on Meta's approval. How a WhatsApp agent will work (webhooks, buttons, the 24-hour window and templates), and how to build on Telegram today with the same code.

<Warning>
  **WhatsApp is not available yet.** Flow is waiting on Meta's approval as a Tech Provider. Until then there is no WhatsApp sandbox and no WhatsApp numbers: `POST /v1/senders` with `"channel": "whatsapp"` answers `501` [`not_implemented`](/errors/not_implemented). Build on [Telegram](/guides/telegram-agent) today; the code below does not change per channel, so it will answer on WhatsApp once it ships.
</Warning>

This page shows how an AI agent will answer people on WhatsApp once it is available: it receives messages, streams the model's answer back as chat bubbles, uses buttons, and handles WhatsApp's 24-hour window.

```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.
</Note>

## 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/v1/sandbox/keys` (or `npx @flow-engineer/messaging init`). Set its `key` as `FLOW_MESSAGING_KEY`. See [Keys and sign-in](/get-a-key).
2. Join the Telegram sandbox from your phone with the bot's `address.link` (see [Build a Telegram agent](/guides/telegram-agent)).
3. Register your webhook, or on your laptop read events from the live stream (`GET /v1/stream`, see [Local development](/guides/local-development)), 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, content, or a list of up to 10
  },
});
```

```json HTTP response body theme={null}
{ "reply": { "type": "text", "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 `POST /v1/conversations/{conversation_id}/messages`.

## 3. Voice notes

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

```json theme={null}
{ "type": "voice", "url": "https://api.flow.engineer/v1/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, send `voice` content with an audio `url` or `file_id`.

## 4. Buttons and lists

WhatsApp will show up to 3 reply buttons, and a list for 4 to 10:

```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 arrives as `message.received` with `button_reply` content: `{ "type": "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`](/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"] }),
);
```

Once WhatsApp numbers are available, templates are created on your dedicated number with `POST /v1/templates` and reviewed by WhatsApp; you receive `template.status_changed` when one is approved, rejected or paused. See [Going live](/guides/going-live#whatsapp-templates).

## 6. What WhatsApp will support

| Content | WhatsApp |
| - | - |
| Text with markdown | yes (rendered in WhatsApp's own formatting) |
| Images, video, documents, audio | yes |
| Voice notes | yes, both ways |
| Buttons | up to 3, else a list (up to 10) |
| Reactions, read receipts, typing | yes |
| Locations, contact cards | yes |
| Edit or unsend | no (`422 unsupported_content`) |

## 7. Going live on WhatsApp

Not possible yet. When WhatsApp ships, Flow will host a dedicated number for you, your business will be verified through Meta, and your agent's code stays the same. Until then, go live on [your own Telegram bot](/guides/going-live), or ask the Flow team about an iMessage line.

<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.
</Warning>

## Related

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


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