Skip to content

Telegram

The Telegram provider allows your digital worker to communicate via Telegram bots. It supports:

  • Text messages
  • Inline keyboards (buttons)
  • Reply keyboards
  • File attachments
  • Media (photos, videos, documents)
  • Group chats
  • A Telegram account
  • A Telegram bot (created via @BotFather)
  1. Create a Telegram bot

    Open Telegram and message @BotFather:

    /newbot

    Follow the prompts:

    • Enter a name for your bot (e.g., “My Support Bot”)
    • Enter a username (must end in bot, e.g., “my_support_bot”)

    BotFather will give you a bot token like:

    123456789:ABCdefGHIjklMNOpqrsTUVwxyz
  2. Configure the provider

    Create or update your answers file:

    answers.json
    {
    "setup_answers": {
    "messaging-telegram": {
    "public_base_url": "https://your-domain.ngrok-free.app",
    "api_base_url": "https://api.telegram.org",
    "telegram_bot_token": "123456789:ABCdefGHIjklMNOpqrsTUVwxyz"
    }
    }
    }
  3. Run setup

    Terminal window
    gtc setup --answers answers.json ./my-bundle
  4. Start the runtime

    Terminal window
    gtc start ./my-bundle
  5. Test your bot

    Open Telegram, find your bot by username, and send a message!

OptionRequiredDescription
public_base_urlYesPublic URL for webhook
api_base_urlYesTelegram API URL, normally https://api.telegram.org
telegram_bot_tokenYesBot token from @BotFather
default_chat_idNoDefault chat id for proactive sends

Telegram uses webhooks for incoming updates and the Telegram Bot API for outgoing sends. Expose the Greentic runtime through HTTPS on port 443; local development can use a tunnel that forwards the public URL to the local runtime port.

DirectionProtocol and portPurpose
IncomingHTTPS 443 from Telegram to GreenticBot webhook updates for messages and callback queries
OutgoingHTTPS 443 from Greentic to api.telegram.org or the configured api_base_urlsetWebhook, message sends, callback answers, and Bot API reads

No Telegram-specific TCP port needs to be opened on the Greentic host. The public webhook URL must be reachable by Telegram over HTTPS.

- id: reply
type: reply
config:
message: "Hello! How can I help you today?"

Telegram supports MarkdownV2:

- id: formatted_reply
type: reply
config:
message: |
*Bold* _Italic_ `Code`
[Link](https://example.com)
parse_mode: MarkdownV2
- id: ask_action
type: reply
config:
message: "What would you like to do?"
buttons:
- row:
- label: "Get Help"
callback_data: "action:help"
- label: "Settings"
callback_data: "action:settings"
- row:
- label: "Contact Support"
url: "https://support.example.com"
- id: ask_choice
type: reply
config:
message: "Choose an option:"
reply_keyboard:
- ["Option A", "Option B"]
- ["Option C", "Cancel"]
resize_keyboard: true
one_time_keyboard: true
- id: send_image
type: reply
config:
photo:
url: "https://example.com/image.jpg"
caption: "Here's your image!"
- id: send_file
type: reply
config:
document:
url: "https://example.com/report.pdf"
filename: "report.pdf"
caption: "Your monthly report"
- id: reply_to_message
type: reply
config:
message: "This is a reply to your previous message"
reply_to_message_id: "{{original_message_id}}"

When a user clicks an inline keyboard button, you receive a callback:

flows/on_callback.ygtc
name: handle_callback
version: "1.0"
nodes:
- id: check_action
type: branch
config:
conditions:
- expression: "callback_data == 'action:help'"
to: show_help
- expression: "callback_data == 'action:settings'"
to: show_settings
default: unknown_action
- id: show_help
type: reply
config:
message: "Here's how I can help..."
- id: show_settings
type: reply
config:
message: "Settings menu..."
- id: unknown_action
type: reply
config:
message: "Unknown action"
triggers:
- type: callback_query
target: check_action

The Telegram provider supports group chats:

greentic.demo.yaml
tenants:
demo:
teams:
support:
channels:
telegram-group:
provider: messaging-telegram
config:
chat_id: "-1001234567890" # Group chat ID
  1. Add your bot to the group
  2. Send a message in the group
  3. Check the webhook payload for chat.id

Or use the Telegram API:

Terminal window
curl "https://api.telegram.org/bot<TOKEN>/getUpdates"

The setup flow automatically configures the webhook:

POST https://api.telegram.org/bot<TOKEN>/setWebhook
{
"url": "https://your-domain.com/v1/messaging/ingress/messaging-telegram/{tenant}/{team}",
"allowed_updates": ["message", "callback_query"],
"secret_token": "optional-shared-secret"
}

If needed, configure manually:

Terminal window
curl -X POST "https://api.telegram.org/bot<TOKEN>/setWebhook" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/v1/messaging/ingress/messaging-telegram/demo/default",
"allowed_updates": ["message", "callback_query"],
"secret_token": "optional-shared-secret"
}'

Telegram sends the configured secret_token back in the X-Telegram-Bot-Api-Secret-Token header. Configure it when your installed pack exposes that field.

  1. Check webhook status:

    Terminal window
    curl "https://api.telegram.org/bot<TOKEN>/getWebhookInfo"
  2. Verify public URL is accessible:

    Terminal window
    curl https://your-domain.ngrok-free.app/health
  3. Check logs:

    Terminal window
    gtc start ./my-bundle --verbose
Error: 401 Unauthorized

Verify your bot token is correct and not expired.

  1. Ensure the bot has been started (user sent /start)
  2. Check if the bot is in the group (for group chats)
  3. Verify webhook URL matches your public URL

Telegram has rate limits:

  • 1 message per second per chat
  • 30 messages per second overall

Handle rate limits gracefully:

- id: reply
type: reply
config:
message: "Response"
retry_on_429: true
max_retries: 3

Telegram sends a secret token with webhook requests. Greentic validates this automatically.

Always validate user input:

- id: validate
type: script
config:
script: |
if message.len() > 4096 {
return error("Message too long")
}
message