Skip to main content
Want your agent on Telegram? You’re about five minutes and three API calls away from having a bot that responds to DMs with the full power of OpenClaw behind it. Here’s the plan: create a Telegram bot, hand Chowder the token, approve the first user, done.
You need a running Chowder instance. If you don’t have one yet, follow Your First Instance to get set up.

Set up your environment

export CHOWDER_KEY="chd_org_your_key_here"
export INSTANCE_ID="your-instance-id"
1
Create a Telegram bot
2
Open Telegram and search for @BotFather — it’s Telegram’s official bot for creating bots (very meta).
3
  • Send /newbot
  • Pick a display name (e.g., “My Chowder Agent”)
  • Pick a username ending in bot (e.g., my_chowder_agent_bot)
  • BotFather replies with your bot token — a string like 7123456789:AAF1k2j3h4g5f6d7s8a9...
  • 4
    Keep this token secret. Anyone with it can control your bot. Don’t commit it to version control.
    5
    Copy the bot token
    6
    Grab the token from BotFather’s message. You’ll pass it to Chowder in the next step.
    7
    export BOT_TOKEN="7123456789:AAF1k2j3h4g5f6d7s8a9..."
    
    8
    Connect the channel
    9
    Call the Telegram connect endpoint with your bot token:
    10
    curl -X POST https://api.chowder.dev/v1/instances/$INSTANCE_ID/channels/telegram/connect \
      -H "Authorization: Bearer $CHOWDER_KEY" \
      -H "Content-Type: application/json" \
      -d "{
        \"config\": {
          \"token\": \"$BOT_TOKEN\"
        }
      }"
    
    11
    {
      "channel": "telegram",
      "status": "connected",
      "qr_data": null,
      "qr_image_base64": null,
      "message": null
    }
    
    12
    That’s it — the channel is live. Behind the scenes, Chowder:
    13
  • Wrote your bot token to the instance’s openclaw.json config under channels.telegram
  • Set enabled: true and dmPolicy: "pairing" (more on that next)
  • Restarted the gateway to pick up the new channel
  • 14
    You can verify this by checking the channel status anytime:
    curl https://api.chowder.dev/v1/instances/$INSTANCE_ID/channels/telegram/status \
      -H "Authorization: Bearer $CHOWDER_KEY"
    
    {
      "channel": "telegram",
      "enabled": true,
      "connected": true,
      "details": null
    }
    
    15
    Understand the DM pairing policy
    16
    OpenClaw uses a pairing system for DM channels. Here’s how it works:
    17
  • Someone sends your bot a message on Telegram
  • OpenClaw generates a pairing code and replies with it in the chat
  • You approve that code through the API (or OpenClaw CLI)
  • Once approved, that Telegram user can chat freely with your agent
  • 18
    This prevents random people from racking up your model costs. The first person to message gets a code, and you decide whether to let them in.
    19
    The pairing code is shown to the user directly in Telegram. You need to get it from them (or see it in the logs) and then approve it via the API.
    20
    Approve a pairing
    21
    Once someone messages your bot and gets a pairing code, approve it:
    22
    curl -X POST https://api.chowder.dev/v1/instances/$INSTANCE_ID/channels/telegram/pair \
      -H "Authorization: Bearer $CHOWDER_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "code": "abc123"
      }'
    
    23
    {
      "channel": "telegram",
      "code": "abc123",
      "status": "approved",
      "output": "Pairing approved for user 123456789."
    }
    
    24
    Now that user can DM your bot and get full agent responses — tools, memory, the works.
    25
    Check channel status
    26
    At any point, you can check whether the Telegram channel is up and healthy:
    27
    curl https://api.chowder.dev/v1/instances/$INSTANCE_ID/channels/telegram/status \
      -H "Authorization: Bearer $CHOWDER_KEY"
    
    28
    {
      "channel": "telegram",
      "enabled": true,
      "connected": true,
      "details": null
    }
    
    29
    You can also list all channels on your instance to see what’s connected:
    30
    curl https://api.chowder.dev/v1/instances/$INSTANCE_ID/channels \
      -H "Authorization: Bearer $CHOWDER_KEY"
    
    31
    [
      {
        "channel": "telegram",
        "connection_type": "token",
        "enabled": true
      },
      {
        "channel": "discord",
        "connection_type": "token",
        "enabled": false
      },
      {
        "channel": "whatsapp",
        "connection_type": "interactive",
        "enabled": false
      }
    ]
    
    32
    Disconnect when done
    33
    If you want to remove the Telegram channel:
    34
    curl -X POST https://api.chowder.dev/v1/instances/$INSTANCE_ID/channels/telegram/disconnect \
      -H "Authorization: Bearer $CHOWDER_KEY"
    
    35
    This returns 204 No Content. Chowder sets enabled: false in the config and restarts the gateway. The bot token is still in the config file but the channel is no longer active.

    How it works under the hood

    When you call the connect endpoint, Chowder does the following on your instance’s sandbox:
    1. Reads the openclaw.json config file
    2. Writes the bot token to channels.telegram.botToken
    3. Enables the channel: channels.telegram.enabled = true
    4. Sets the DM policy: channels.telegram.dmPolicy = "pairing"
    5. Restarts the gateway process so it picks up the new config
    The gateway then starts a Telegram bot listener using the Telegram Bot API. Incoming DMs are routed to the agent, and responses are sent back through the bot.

    Other channels

    Telegram is a “token-based” channel — you give it a token, it connects. Chowder supports a bunch of these:
    These work the same way as Telegram — pass credentials via the connect endpoint:
    ChannelRequired fields
    Telegramtoken (bot token from BotFather)
    Discordtoken (bot token)
    Slackbot_token + app_token (for Socket Mode)
    Signalaccount (E.164 phone number)
    Matrixhomeserver + user_id + access_token
    MS Teamsapp_id + app_password + tenant_id
    Mattermostbot_token + base_url
    LINEchannel_access_token + channel_secret
    Google Chataudience_type + audience

    What’s next?