Skip to content

Updating visuals

If you see any images containing outdated UI, please bear with us.

We are updating all content as quickly as possible to mirror our new UI.

Telegram integration ​

Telegram lets your app message users through a Telegram bot: send texts, photos, documents and inline keyboards, edit or delete messages, and react to incoming messages and button taps via webhook triggers.

Use cases ​

  • Send notifications to users or groups (order updates, alerts, reminders)
  • Build a support or assistant bot that replies to incoming messages
  • Send interactive messages with inline keyboard buttons and react to taps
  • Deliver files and images (reports, invoices, media) from backend workflows

Setup ​

  1. Open @BotFather in Telegram — BotFather is Telegram's official bot for creating and managing other bots — and send it the /newbot command.
  2. Choose a name and a username for your bot — BotFather replies with an API token.
  3. In WeWeb, open the Data & API tab, then the Integrations subtab. Select Telegram, then click Add Connection.
  4. Paste the Bot Token and click Verify — WeWeb confirms which bot the token belongs to. The connection applies to all environments (Editor, Staging, Production); to use different values per environment, override the generated environment variables.
  5. Test by sending a message: open a chat with your bot in Telegram, send it any message (a bot cannot message you first), then use Send Message with your chat ID.

Enabling triggers (webhook) ​

The two triggers (see below) require the connection's webhook:

  1. On the connection, set Telegram Webhook to Enabled and keep (or adjust) the Webhook Path (default /telegram/webhook).
  2. Save the connection and publish your project — the webhook route only exists after publishing.
  3. Click Set webhook on the connection. WeWeb registers the webhook with Telegram, including a secret token used to verify incoming requests.

ONE BOT TOKEN PER ENVIRONMENT

A Telegram bot holds a single webhook URL. Clicking Set webhook from one environment overwrites the webhook of the others and silently kills their triggers. If you use triggers in more than one environment, create a separate bot (and token) per environment.

Triggers ​

With the webhook enabled and set, two backend triggers become available:

On message received ​

Runs each time someone sends a message to your bot — e.g. reply with Send Message bound to event.chat.id.

Example event

json
{
  "message_id": 2,
  "from": { "id": 123456789, "is_bot": false, "first_name": "Jane", "language_code": "en" },
  "chat": { "id": 123456789, "first_name": "Jane", "type": "private" },
  "date": 1787574749,
  "text": "Hello"
}

On button tapped ​

Runs when someone taps, in Telegram, an inline keyboard button that carries a callback_data value. You attach these buttons to a message through the Inline keyboard input of the Send Message, Send Photo, Send Document and Edit Message Text actions in WeWeb (see Inline keyboards). Answer the tap with Answer Callback Query bound to event.id — until answered, the user sees a loading spinner on the button. Branch on event.data (the button's callback_data) to route different buttons in one workflow.

Example event

json
{
  "id": "4382156871125391245",
  "from": { "id": 123456789, "is_bot": false, "first_name": "Jane", "language_code": "en" },
  "message": {
    "message_id": 5,
    "chat": { "id": 123456789, "first_name": "Jane", "type": "private" },
    "date": 1787574749,
    "text": "Pick an option"
  },
  "data": "confirm"
}

Inline keyboards ​

Send Message, Send Photo, Send Document and Edit Message Text accept an Inline keyboard input — the buttons shown under a message. Its value is a JSON object with a single inline_keyboard key holding an array of rows, where each row is an array of buttons displayed side by side. Every button needs a text (the label) plus one behavior:

  • url — Tapping the button opens that link;
  • callback_data — Tapping the button fires the On button tapped trigger, with this value available as event.data (max 64 bytes).
json
{
  "inline_keyboard": [
    [
      { "text": "Confirm", "callback_data": "confirm" },
      { "text": "Cancel", "callback_data": "cancel" }
    ],
    [
      { "text": "Open website", "url": "https://example.com" }
    ]
  ]
}

This example renders two rows under the message: Confirm and Cancel next to each other on the first row, and a link button on the second.

Common pitfalls (setup & usage) ​

Bots cannot message a user first ​

Sending to a user who never started your bot fails with 403 bot can't initiate conversation with a user, and an unknown chat ID fails with 400 chat not found. The user must have started the bot (or share a group with it). Chat IDs usually come from trigger events (event.chat.id) — there is no API to list a bot's chats.

MarkdownV2 formatting errors ​

MarkdownV2 requires escaping special characters (., !, -, (, ), #, etc.) with \, and unescaped characters fail with a 400 error — the most common send failure. For dynamic content, prefer HTML formatting (<b>, <i>, <a href>) or plain text.

Media URL fails to load ​

Telegram fetches photo and document URLs server-side. Auth-gated links or URLs that return an HTML page fail with 400 failed to get HTTP URL content. Use a publicly accessible direct file URL (max 5 MB for photos, 20 MB for documents by URL), or reuse the file_id of an already-sent file.

Posting to a channel requires admin rights ​

You can use a channel username (@channelusername) as the Chat ID, but only after adding the bot as an administrator of that channel (channel info → Administrators → Add Admin, with permission to post). A bot can only belong to a channel as an administrator, so as long as it has not been added, sending fails with 400 chat not found even though the username is correct. Private channels have no public username — use their numeric chat ID instead.

A bot can only feed one tool at a time ​

Telegram gives each bot a single webhook address, and setting a new one silently replaces whatever was there before. So if the bot you connect is already used somewhere else (an n8n workflow, a service you linked through @BotFather, your own server), clicking Set webhook in WeWeb takes those messages over: the other tool stops receiving anything at all, with no error shown on either side. It works the same way in reverse, so pointing that bot at another tool later will quietly kill your WeWeb triggers. Some tools read a bot's messages by asking Telegram for them at regular intervals rather than through a webhook, and that method stops working too once a webhook is set. When the other integration still needs to run, create a second bot with @BotFather and use that one in WeWeb.

Group privacy mode ​

By default, a bot in a group only receives commands, replies to its own messages, and messages that mention it. To receive all group messages, disable privacy mode via @BotFather with /setprivacy.

Callback queries expire in seconds ​

Answer every On button tapped trigger with Answer Callback Query first, then do slower work. Late answers fail with 400 query is too old, and unanswered buttons show a spinner to the user for ~30 seconds.

All Actions ​

This integration provides seven actions mapped to the Telegram Bot API.

ActionDescription
Send MessageSend a text message, optionally formatted and with an inline keyboard
Send PhotoSend a photo by public URL or Telegram file_id
Send DocumentSend a file of any type by public URL or Telegram file_id
Edit Message TextEdit the text (and inline keyboard) of a message the bot sent
Delete MessageDelete a message
Get ChatGet up-to-date information about a chat
Answer Callback QueryAnswer an inline keyboard button tap

Action details ​

Send Message ​

Send a text message from the bot to a chat, optionally formatted (MarkdownV2/HTML) and with an inline keyboard.

Inputs

Display KeyExample InputDescriptionRestrictions
Chat ID"123456789"Unique identifier of the target chat, or a channel username (@channelusername — the bot must be an administrator of that channel to post). Usually bound from a trigger event (event.chat.id).Required; the user must have started the bot
Text"Your order has shipped!"Text of the message.1–4096 characters after parsing
Formatting
Optional
"HTML"How Telegram parses the text. Empty = plain text.Valid: MarkdownV2, HTML
Reply to message ID
Optional
42Send this message as a reply to another message in the same chat.Number
Inline keyboard
Optional
{"inline_keyboard":[[{"text":"Confirm","callback_data":"confirm"}]]}Buttons shown under the message — see Inline keyboards for the structure. Tapping a callback_data button fires the On button tapped trigger.Valid InlineKeyboardMarkup object
Send silently
Optional
falseUsers receive the message without a notification sound.Boolean
Protect content
Optional
falsePrevents the message from being forwarded or saved.Boolean

Example output

json
{
  "message_id": 2,
  "chat": { "id": 123456789, "type": "private" },
  "date": 1787574749,
  "text": "Your order has shipped!"
}

Documentation of API endpoint that powers action: Telegram Bot API – sendMessage (POST /sendMessage)

Send Photo ​

Send a photo from the bot to a chat, by public URL or Telegram file_id.

Inputs

Display KeyExample InputDescriptionRestrictions
Chat ID"123456789"Unique identifier of the target chat, or a channel username.Required
Photo"https://example.com/image.jpg"A publicly accessible image URL (Telegram fetches it server-side) or a Telegram file_id of an already-sent photo.Max 5 MB by URL
Caption
Optional
"Our new office!"Photo caption.0–1024 characters after parsing
Formatting
Optional
"HTML"How Telegram parses the caption. Empty = plain text.Valid: MarkdownV2, HTML
Reply to message ID
Optional
42Send as a reply to another message in the same chat.Number
Inline keyboard
Optional
{"inline_keyboard":[[{"text":"View","url":"https://example.com"}]]}Buttons shown under the message — see Inline keyboards.Valid object
Send silently
Optional
falseNo notification sound.Boolean
Protect content
Optional
falsePrevents forwarding or saving.Boolean

Example output

json
{
  "message_id": 3,
  "chat": { "id": 123456789, "type": "private" },
  "date": 1787574749,
  "photo": [ { "file_id": "AgADAgADwqcxGy…", "width": 320, "height": 320 } ],
  "caption": "Our new office!"
}

Documentation of API endpoint that powers action: Telegram Bot API – sendPhoto (POST /sendPhoto)

Send Document ​

Send a file (any type) from the bot to a chat, by public URL or Telegram file_id.

Inputs

Display KeyExample InputDescriptionRestrictions
Chat ID"123456789"Unique identifier of the target chat, or a channel username.Required
Document"https://example.com/report.pdf"A publicly accessible file URL (Telegram fetches it server-side) or a Telegram file_id of an already-sent file.Max 20 MB by URL
Caption
Optional
"Monthly report attached"Document caption.0–1024 characters after parsing
Formatting
Optional
"HTML"How Telegram parses the caption. Empty = plain text.Valid: MarkdownV2, HTML
Reply to message ID
Optional
42Send as a reply to another message in the same chat.Number
Inline keyboard
Optional
{"inline_keyboard":[[{"text":"Open","url":"https://example.com"}]]}Buttons shown under the message — see Inline keyboards.Valid object
Send silently
Optional
falseNo notification sound.Boolean
Protect content
Optional
falsePrevents forwarding or saving.Boolean

Example output

json
{
  "message_id": 4,
  "chat": { "id": 123456789, "type": "private" },
  "date": 1787574749,
  "document": { "file_id": "BQADAgADy6cxGy…", "file_name": "report.pdf", "mime_type": "application/pdf" },
  "caption": "Monthly report attached"
}

Documentation of API endpoint that powers action: Telegram Bot API – sendDocument (POST /sendDocument)

Edit Message Text ​

Edit the text (and optionally the inline keyboard) of a message previously sent by the bot.

Inputs

Display KeyExample InputDescriptionRestrictions
Chat ID"123456789"The chat containing the message.Required
Message ID42Identifier of the target message (message_id from a sent or received message).Required
New text"Order status: shipped ✅"New text of the message.1–4096 characters after parsing
Formatting
Optional
"HTML"How Telegram parses the new text. Empty = plain text.Valid: MarkdownV2, HTML
Inline keyboard
Optional
{"inline_keyboard":[[{"text":"Track","url":"https://example.com"}]]}Replace the message's inline keyboard — see Inline keyboards.Valid object

Editing a message with identical content fails with 400 message is not modified — guard workflows that might re-apply the same edit.

Example output

json
{
  "message_id": 42,
  "chat": { "id": 123456789, "type": "private" },
  "date": 1787574749,
  "text": "Order status: shipped ✅"
}

Documentation of API endpoint that powers action: Telegram Bot API – editMessageText (POST /editMessageText)

Delete Message ​

Delete a message. Only works within 48 hours of the message being sent (including the bot's own messages); deleting others' messages additionally requires the bot to be a group admin.

Inputs

Display KeyExample InputDescriptionRestrictions
Chat ID"123456789"The chat containing the message.Required
Message ID42Identifier of the message to delete.Required; within 48h of sending

Example output

json
true

Documentation of API endpoint that powers action: Telegram Bot API – deleteMessage (POST /deleteMessage)

Get Chat ​

Get up-to-date information about a chat (private chat, group, supergroup or channel).

Inputs

Display KeyExample InputDescriptionRestrictions
Chat ID"123456789"Unique identifier of the chat, or a channel username.Required

Example output

json
{
  "id": 123456789,
  "type": "private",
  "first_name": "Jane",
  "username": "janed"
}

Documentation of API endpoint that powers action: Telegram Bot API – getChat (POST /getChat)

Answer Callback Query ​

Answer a callback query from an inline keyboard button tap. Call it after every On button tapped trigger — until answered, the user sees a loading spinner on the button.

Inputs

Display KeyExample InputDescriptionRestrictions
Callback query ID"4382156871125391245"Identifier of the query to answer — bind event.id from the On button tapped trigger.Required; queries expire within seconds
Notification text
Optional
"Done!"Text shown to the user as a notification at the top of the chat. Empty = just stop the spinner.0–200 characters
Show as alert
Optional
falseShow the text as a modal alert instead of a passing notification.Boolean
Cache time (seconds)
Optional
0Maximum time Telegram clients may cache this answer, in seconds.Number

Example output

json
true

Documentation of API endpoint that powers action: Telegram Bot API – answerCallbackQuery (POST /answerCallbackQuery)

Error handling ​

Error code and typeReason
400 Bad RequestUnknown chat (chat not found), unreachable media URL (failed to get HTTP URL content), unescaped MarkdownV2 characters, identical edit (message is not modified), or late callback answer (query is too old).
401 UnauthorizedInvalid bot token.
403 ForbiddenThe user never started the bot (bot can't initiate conversation with a user), or the bot was blocked or lacks group permissions.
429 Too Many RequestsRate limited — the response includes parameters.retry_after (seconds to wait). Telegram allows roughly 1 message/second per chat, 20/minute per group, and ~30/second overall.

FAQs ​

How do I find my chat ID?

Enable the webhook, send a direct message to your bot, and read event.chat.id from the On message received trigger event. There is no API to list a bot's chats.

Why don't my triggers fire?

Check, in order: the webhook is Enabled on the connection, the project has been published (the webhook route only exists after publishing), and you clicked Set webhook afterwards. Also note a bot has a single webhook URL — setting the webhook from another environment overwrites it.

Should I use MarkdownV2 or HTML formatting?

For dynamic content, prefer HTML (<b>, <i>, <a href>): MarkdownV2 requires escaping many special characters with \ and unescaped input fails with a 400 error. If you don't need styling, leave Formatting empty for plain text.

Why doesn't my bot see group messages?

Group privacy mode is on by default: the bot only receives commands, replies to its own messages, and mentions. Disable privacy via @BotFather with /setprivacy to receive all group messages.

How do I send interactive buttons and react to taps?

Send a message with an Inline keyboard whose buttons carry callback_data (structure explained here). When a user taps one, the On button tapped trigger fires with the button's callback_data in event.data — answer it with Answer Callback Query (bound to event.id) first, then run your logic.

Can I upload a file directly from a workflow?

No — media is sent by public URL (or by reusing a Telegram file_id from a previously sent file). Binary upload from workflows is not supported.