Skip to main content
Try your agent on the Telegram sandbox, then connect your own bot without changing its message handler.
TypeScript

1. Try it on the 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. It allows 1 contact and 50 messages for 7 days; sign in to get more (Keys and sign-in).
  2. GET /v0/senders?channel=telegram lists the sandbox bot. Its address.link is https://t.me/<bot>?start=<code>, with your join code in it. (npx @flow-engineer/messaging init prints it too.)
  3. Open the link and tap Start. That’s it, you’ve joined: your app gets conversation.started, then /start as your first message.received.
  4. Run the code above and send the bot a message.
If the link can’t be used (for example you found the bot by searching for it), send the bot the sender’s join_code instead, as it is, for example Hi Sandbox app (ref wild-otter-04508705).

2. Your own Telegram bot

Telegram is the fastest channel to go live on: bring a bot token and it is connected at once.
  1. In Telegram, open @BotFather, send /newbot, and copy the token.
  2. Put the token in an environment variable on your server or in your terminal, and connect it with a live key (FLOW_MESSAGING_KEY=fk_live_...):
curl
Flow checks the token, keeps it encrypted, points the bot’s webhook at Flow and answers with the sender active. The token is never returned. With FLOW_MESSAGING_KEY set to the live key, your agent now answers on your bot.
The bot token controls your bot. Never paste it into a chat with an AI assistant (including your coding agent), and never commit it. Keep it in an environment variable and send it from your own server or terminal, as above.
To disconnect the bot, call DELETE /v0/senders/{sender_id} with your live key: Flow removes the bot’s webhook, deletes its token and retires the sender (banned). If Telegram rejects the token (you revoked it in @BotFather), the sender turns flagged: new sends answer 403 permission and queued messages are held. Send the new token the same way (POST /v0/senders) and the same sender becomes active again and sends them. A held message waits at most 72 hours after Flow accepted it; after that it fails with outside_window (channel_code queued_too_long) in message.failed instead of going out late.
A bot can have only one webhook. Connecting a bot to Flow replaces any webhook it had, so do not keep another server polling or receiving updates for the same bot.

3. Inline keyboards

A buttons message shows as an inline keyboard (1 to 10 buttons). Taps arrive as button_reply with the button’s id. URL buttons open a link and send nothing back. Telegram has no list or carousel: those answer 422 unsupported_content, and the hint says what to send instead (for a carousel, a basic message, then one buttons message with an image header per card).
TypeScript

4. Edit and unsend

Telegram lets bots edit their messages at any time and unsend them within 48 hours of sending:
TypeScript
An unsend more than 48 hours after sending is refused at once with 422 unsupported_content and channel_code unsend_window_closed; send a new message instead. A 200 means accepted: wait for message.sent (or message.failed) for the unsend. See Edit and unsend limits.

5. What Telegram supports

6. Telegram rules worth knowing

  • People must start your bot first. Telegram does not let a bot message someone who has never pressed Start.
  • Commands are messages. /start and other commands arrive as basic messages; your agent decides what to answer.
  • Contacts have no phone number. A Telegram contact is identified by address.telegram_user_id and maybe address.username.