Telegram ExecModule
Overview
TelegramModule connects ValkyrAI workflows to the Telegram Bot API through the native map I/O ExecModule ABI. Workflow Studio discovers it as TelegramModule; the bot token resolves only from an encrypted IntegrationAccount.
The initial production operation set covers bot, chat, member, file-metadata, message, pin, and callback workflows:
get_me,get_chat,get_chat_administrators, andget_chat_memberget_filesend_message,edit_message_text, and guardeddelete_messagepin_chat_messageandunpin_chat_messageanswer_callback_query
Read-only operations can retry transient Telegram failures. Message sends, edits, deletes, pins, unpins, and callback answers run once so an ambiguous timeout cannot duplicate or repeat a side effect.
Usage
- Create a bot through Telegram BotFather and keep the generated bot token private.
- Add the bot to the intended chat or channel and grant only the permissions required by the selected operations.
- Store the bot token in the encrypted
apiKeyfield of anIntegrationAccount. - Set the account status to
READYand bind it throughExecModuleConfig.authConfig.integrationAccount. - Run
get_me, thenget_chat, to verify the bot identity and destination before a mutation. - Use a numeric chat ID for private chats and groups or a public
@channelusernamewhere Telegram accepts one. - Reconcile Telegram state before repeating any write after an ambiguous connection failure.
Workflow input cannot provide a bot token or arbitrary provider endpoint. Production routing is fixed to api.telegram.org over HTTPS.
Inputs
| Name | Type | Requirement | Default | Description and constraints |
|---|---|---|---|---|
operation | string | Required | None | One of the 11 documented operations. |
chatId | string | Chat/message operations | None | Numeric chat ID or public @username, maximum 128 characters. |
messageId | positive integer | Edit/delete/pin/unpin | None | Telegram message identifier. |
userId | positive integer | get_chat_member | None | Telegram user identifier. |
fileId | string | get_file | None | Opaque provider file ID, maximum 1,024 characters. |
callbackQueryId | string | answer_callback_query | None | Opaque callback-query ID, maximum 1,024 characters. |
text | string | Send/edit; optional callback | None | 1–4,096 characters for messages and at most 200 for callback answers. |
parseMode | string | Optional send/edit | none | none, HTML, or MarkdownV2. |
replyMarkup | object or JSON string | Optional send/edit | None | Inline or reply keyboard fields, 128 KiB maximum and eight nesting levels. |
messageThreadId | positive integer | Optional send | None | Forum topic/thread identifier. |
replyToMessageId | positive integer | Optional send | None | Message to reply to. |
disableNotification | boolean | Optional send/pin | false | Requests silent delivery or pin behavior. |
protectContent | boolean | Optional send/edit | false | Prevents forwarding and saving where Telegram supports it. |
showAlert | boolean | Optional callback | false | Shows callback text as an alert. |
callbackUrl | HTTPS URL | Optional callback | None | Client URL Telegram should open after the callback answer. |
cacheTime | integer | Optional callback | 0 | Callback caching window in seconds, 0–86,400. |
confirmDelete | boolean | delete_message | false | Must be true before the delete request is sent. |
replyMarkup accepts only inline_keyboard, keyboard, remove_keyboard, force_reply, resize_keyboard, one_time_keyboard, selective, input_field_placeholder, and is_persistent at the top level. Credential-like nested keys, excessive arrays, deep nesting, and oversized text fail before a provider request.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation name. |
attempts | integer | Always | Total provider attempts. |
httpStatus | integer | Provider responded | Last Telegram HTTP status. |
data | object, array, or boolean | Success | Telegram's normalized result value. |
id | integer | Identity/chat result | Safe convenience identifier. |
messageId | integer | Message result | Telegram message_id. |
fileId / filePath | string | File metadata result | Opaque file ID and provider-relative path; bytes are not downloaded. |
resourceStatus | string | Member result | Telegram membership status. |
count | integer | Array result | Number of returned administrators. |
error | object | Failure | Safe code, redacted message, optional HTTP status, and retryable flag. |
The bot token and token-bearing request path never enter outputs. Provider error descriptions pass through ValkyrAI's sensitive-data redaction policy.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | Telegram bot created through BotFather |
| Chat access | Bot added to the intended private chat, group, supergroup, or channel |
| Permissions | Read/admin/message/pin/delete permissions limited to selected operations |
apiKey | Bot token in an encrypted SecureField |
password | Legacy encrypted bot-token fallback only; prefer apiKey |
accountId | Optional organizational label; not used as a chat ID |
status | READY or legacy unset status; CLOSED and ERROR fail closed |
Bot creation, token rotation, revocation, chat installation, privacy-mode configuration, and admin promotion belong to the platform IntegrationAccount lifecycle and Telegram administration. Workflow inputs never handle credentials.
Configuration
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:telegram-operations-bot"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000,
"jitter": false
},
"executionConfig": {"timeoutMs": 30000},
"payloadConfig": {
"parameters": "{\"operation\":\"get_chat\",\"chatId\":\"-1001234567890\"}"
}
}
The integration-account value is symbolic. Persisted workflows use the generated relationship rather than a plaintext bot token.
Operations
| Operation | Telegram behavior | Side effect |
|---|---|---|
get_me | Reads the authenticated bot identity. | Read-only; safe retries. |
get_chat | Reads one chat's current metadata. | Read-only; safe retries. |
get_chat_administrators | Returns current non-bot and bot administrators. | Read-only; safe retries. |
get_chat_member | Reads one user's membership and permissions. | Read-only; safe retries. |
get_file | Resolves file metadata and provider-relative path. | Read-only; safe retries; does not download bytes. |
send_message | Sends one bounded text message with optional markup. | Creates a message; single attempt. |
edit_message_text | Replaces text and optional markup for one message. | Mutates a message; single attempt. |
delete_message | Deletes one message after explicit confirmation. | Destructive; single attempt. |
pin_chat_message | Pins one message with explicit notification behavior. | Mutates chat state; single attempt. |
unpin_chat_message | Unpins one message. | Mutates chat state; single attempt. |
answer_callback_query | Answers one inline-keyboard callback. | User-visible response; single attempt. |
Errors and Failure Modes
| Code | Typical cause | Retryable | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Missing/invalid ID, message, URL, markup, token format, or deletion guard. | No | Correct input; no unsafe provider request was sent. |
UNSUPPORTED_OPERATION | Unknown operation. | No | Select a documented operation. |
INTEGRATION_ACCOUNT_REQUIRED | No bound account. | No | Bind a Telegram IntegrationAccount. |
INTEGRATION_ACCOUNT_NOT_READY | Account is closed or in error. | No | Repair or replace the account. |
CREDENTIAL_MISSING | Bound account has no decryptable token. | No | Reconnect or rotate the bot token. |
TELEGRAM_API_400 | Invalid request, inaccessible chat, or unsupported combination. | No | Correct the safe provider detail and re-read chat state. |
TELEGRAM_API_401 | Invalid or revoked bot token. | No | Rotate and update the IntegrationAccount. |
TELEGRAM_API_403 | Bot blocked, removed, or missing chat permission. | No | Repair chat membership and permissions. |
TELEGRAM_API_404 | Chat, message, user, callback, or file is absent. | No | Re-read with the same bot identity. |
TELEGRAM_API_429 / 5xx | Telegram rate limit or transient provider failure. | Yes for reads | Honor retry_after; reconcile writes before repeating them. |
NETWORK_ERROR | Timeout, DNS, TLS, or connectivity failure. | Yes for reads | Verify connectivity and provider state. |
PAYLOAD_TOO_LARGE | Request exceeded 128 KiB. | No | Reduce message markup or inputs. |
RESPONSE_TOO_LARGE | Response exceeded 5 MiB. | No | Narrow the operation or chat context. |
Example
Send one approved production activation update:
{
"operation": "send_message",
"chatId": "-1001234567890",
"text": "Production activation completed and public verification passed.",
"disableNotification": true,
"protectContent": true,
"replyMarkup": {
"inline_keyboard": [[
{
"text": "Open documentation",
"url": "https://valkyrlabs.com/v1/valkyrai/workflow-engine/execmodules/telegram"
}
]]
}
}
Expected result:
{
"status": "success",
"operation": "send_message",
"attempts": 1,
"httpStatus": 200,
"messageId": 42,
"data": {
"message_id": 42,
"text": "Production activation completed and public verification passed."
}
}
Notes
- Pagination: these Bot API operations do not expose provider page tokens. Administrator arrays are returned as one bounded provider response and remain subject to the 5 MiB response cap.
- Rate limits: read-only operations retry HTTP 408, 429, 500, 502, 503, and 504 plus Telegram
error_code429/5xx according toRetryPolicy. Numeric Telegramparameters.retry_afteris honored. Mutations never retry automatically. - API limits: request bodies are capped at 128 KiB, responses at 5 MiB, messages at 4,096 characters, callback text at 200, callback cache time at 86,400 seconds, markup nesting at eight levels, and markup arrays at 500 entries.
- Idempotency: Telegram's initial send/edit/delete/pin/unpin/callback methods do not accept a universal caller idempotency key. Each write is single-attempt; reconcile by bot identity, chat ID, message ID, or callback state before any retry after an ambiguous failure.
- Destructive behavior: only
delete_messageis destructive and requiresconfirmDelete=true. Telegram also applies age, dice, service-message, and bot-permission limits that can reject deletion. - Security: credentials remain in
IntegrationAccountSecureFields. Fixed-host routing, strict bot-token validation, bounded identifiers, allowlisted markup, forbidden credential-like nested keys, capped payloads/responses, and redacted provider descriptions prevent arbitrary routing and secret reflection. - API behavior: public usernames, private chat IDs, supergroup migrations, forum topics, bot privacy mode, channel administrator rights, callback expiry, and Telegram's evolving Bot API rules can impose constraints beyond local validation.
- External verification: request construction, normalization, read retry, single-attempt writes, deletion guards, fixed-host routing, redaction, validation, and metadata discovery have deterministic local tests. Live BotFather creation, chat installation, permissions, delivery, callbacks, deletion windows, rate limits, and token rotation require separately authorized Telegram credentials and are not exercised in repository tests.
- Deferred operations: webhook/long-poll triggers,
getUpdates, arbitrary methods, file-byte download, multipart media upload, albums, polls, reactions, stickers, forum-topic administration, invite links, payments, games, passport flows, business connections, and bot-command/menu administration. - Functional references: n8n Telegram node source, n8n Telegram operations, and Telegram Bot API.