Skip to main content
This page gets an agent answering messages on your phone in about 5 minutes: get a test key, join the shared Telegram sandbox, receive a message, and reply. The same code later answers on your own Telegram bot, and on an iMessage line the Flow team connects for you (WhatsApp is coming).
That one command gets a test key with no account, saves it to .env as FLOW_MESSAGING_KEY (with FLOW_CLAIM_TOKEN), offers to set up your coding agent (skill, AGENTS.md, MCP server; it asks you first), and prints the sandbox link and join code. It asks before setting up your coding agent; --yes skips the question. The steps below do the same by hand and then build the agent.
1

Get a test key

Already have one in FLOW_MESSAGING_KEY? Skip this step. Otherwise get one in one call, with no account:
The answer holds key (fk_test_...) and claim_token (fct_...), both shown once, plus your app (with its sandbox_join_code) and the sandbox senders. Save them:
Test keys reach only the shared sandbox, so nothing reaches anyone who has not joined it. This key allows 1 contact and 50 messages on the Telegram sandbox and expires after 7 days; sign in with GitHub (npx @flow-engineer/messaging login) to keep the app and send 100 messages to each of 3 contacts. See Keys and sign-in.Check the key, and read your app’s sandbox join code and what is left of its allowance:
The answer includes app.sandbox_join_code, for example wild-otter-04508705, and allowance.
2

Join the sandbox from your phone

List the sandbox senders your key can use (today, the Telegram sandbox bot):
Each shared sender has an address.link and a join_code. Open the link on your phone:
  • Telegram: the link is https://t.me/<bot>?start=<code>. Open it and tap Start. That’s it, you’ve joined.
  • If the link can’t be used (for example you found the bot by searching for it): send the sender’s join_code to it, for example:
Your app now has a conversation with you, and you receive a conversation.started event. The join code is how a shared sandbox sender knows which app a person belongs to, so no stranger is ever messaged. See Senders.
3

Receive a message and reply

Run one of these, then send any message to the sandbox sender from your phone. Each program waits for message.received events and answers into the same conversation.
The send answers 202 with the queued message. Its progress may arrive as message.sent, message.delivered and message.read events, depending on what the channel reports. To know how a send ended, wait for message.sent or message.failed: every channel reports one of them.
4

Answer with your model

Replace the echo with your agent. In TypeScript, pass the model’s stream straight to reply(): it keeps the typing indicator on and sends the answer as chat bubbles while the model writes.
TypeScript
Without the SDK, split the answer at paragraph breaks and send each part as its own message, as Streaming replies describes.

What you built

  • A test-mode agent that answers anyone who joined your app on the Telegram sandbox. The code does not change per channel: it answers the same way on your own Telegram bot or an iMessage line.
  • It reads events from the live stream (TypeScript) or the event log (HTTP). In production most agents use webhooks instead, and can answer straight in the webhook response.

Next steps

Events and webhooks

Signed deliveries, retries, ordering, and replying in the response.

Local development

Receive events on your laptop with no public URL through the live stream.

Content types

Media, voice notes, buttons, reactions and what each channel shows.

Going live

A live key, your own Telegram bot, and iMessage lines.