Set Up OpenClaw Telegram Bot with Webhooks in 25 Minutes

Configure a self-hosted AI assistant on Telegram with secure webhooks, pairing, and proper authentication for production use.

Problem: Telegram Bots on Polling Are Slow and Unreliable

You installed OpenClaw and it works on Telegram, but messages take 2-5 seconds to arrive because you're using long-polling instead of webhooks. Production setups need instant delivery and secure endpoints.

You'll learn:

  • Set up Telegram webhooks with proper HTTPS
  • Secure your bot with webhook secrets and pairing codes
  • Configure reverse proxy for external access
  • Troubleshoot common webhook failures

Time: 25 min | Level: Intermediate


Why This Happens

OpenClaw defaults to long-polling for simplicity—no public URL needed, works behind NAT. But polling checks for messages every few seconds, adding latency. Webhooks let Telegram push messages instantly to your server, but require HTTPS and a public endpoint.

Common symptoms:

  • 2-5 second delays before bot responds
  • Messages arrive out of order under load
  • Higher resource usage from constant polling
  • Can't scale beyond basic personal use

Prerequisites

Before starting, ensure you have:

  • OpenClaw installed and running (openclaw gateway status shows active)
  • Node.js 22+ installed
  • A domain name or public IP
  • SSL/TLS certificate (Let's Encrypt works)
  • Telegram bot token from @BotFather

Not setup yet? Run curl -fsSL https://openclaw.ai/install.sh | bash first.


Solution

Step 1: Create Your Telegram Bot

Open Telegram and message @BotFather:

/newbot
# Follow prompts:
# - Bot name: "My OpenClaw Assistant"
# - Username: "my_openclaw_bot" (must end with "bot")

Save the token: You'll see something like 7123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw

Expected: BotFather confirms creation and provides your bot token.


Step 2: Configure Webhook URL and Secret

OpenClaw needs your public HTTPS endpoint. Generate a secure webhook secret:

# Generate strong random secret
openssl rand -hex 32

Add to your OpenClaw config at ~/.openclaw/config.json:

{
  "channels": {
    "telegram": {
      "botToken": "7123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw",
      "webhookUrl": "https://yourdomain.com/webhook/telegram",
      "webhookSecret": "your-generated-secret-here",
      "dmPolicy": "allowlist",
      "allowFrom": []
    }
  }
}

Why this works: webhookSecret ensures only Telegram can send to your endpoint. Without it, anyone could spam fake messages to your bot.

If it fails:

  • Error: "Invalid webhook URL": Must start with https:// (not http://)
  • Error: "Certificate verify failed": Self-signed certs don't work—use Let's Encrypt

Step 3: Set Up Reverse Proxy (Nginx)

Telegram needs HTTPS, but OpenClaw runs HTTP on port 18789. Use Nginx as a reverse proxy:

# /etc/nginx/sites-available/openclaw
server {
    listen 443 ssl http2;
    server_name yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location /webhook/telegram {
        # Verify webhook secret in header
        if ($http_x_telegram_bot_api_secret_token != "your-generated-secret-here") {
            return 403;
        }

        proxy_pass http://127.0.0.1:18789/webhook/telegram;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        
        # Rate limiting to prevent abuse
        limit_req zone=webhook burst=20 nodelay;
    }
}

# Rate limit zone definition (add to http block)
limit_req_zone $binary_remote_addr zone=webhook:10m rate=10r/s;

Enable and reload:

sudo ln -s /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Expected: nginx -t shows "test is successful"


Step 4: Register Webhook with Telegram

Tell Telegram to use webhooks instead of polling:

curl -X POST "https://api.telegram.org/bot7123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/setWebhook" \
  -d "url=https://yourdomain.com/webhook/telegram" \
  -d "secret_token=your-generated-secret-here"

Verify it worked:

curl "https://api.telegram.org/bot7123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw/getWebhookInfo"

You should see:

{
  "ok": true,
  "result": {
    "url": "https://yourdomain.com/webhook/telegram",
    "has_custom_certificate": false,
    "pending_update_count": 0
  }
}

If it fails:

  • pending_update_count > 100: Old polling updates stuck. Run deleteWebhook first
  • last_error_message present: Check Nginx logs with sudo tail -f /var/log/nginx/error.log

Step 5: Pair Your Telegram Account

OpenClaw requires explicit pairing for security. Message your bot /start in Telegram.

Expected: Bot sends back a 6-digit pairing code like ABC123

In your Terminal, approve the pairing:

openclaw pairing approve telegram ABC123

You should see: Approved telegram sender <your-user-id>

Test it: Send any message to your bot—response should arrive in under 500ms.


Verification

Check webhook is receiving messages:

# Watch OpenClaw logs in real-time
openclaw logs --follow

# Should see:
# [Telegram] Webhook received from 123456789
# [Agent] Processing message: "Hello"

Benchmark response time:

# Send message and time response
time curl -X POST "https://api.telegram.org/bot<TOKEN>/sendMessage" \
  -d "chat_id=<YOUR_ID>" \
  -d "text=ping"

You should see: Total time under 1 second (vs 2-5s with polling)


Security Hardening

Enable Group Message Filtering

By default, bots see all group messages if privacy mode is disabled. Lock it down:

{
  "channels": {
    "telegram": {
      "groups": {
        "-1001234567890": {}  // Specific group ID only
      },
      "groupPolicy": "allowlist",
      "groupAllowFrom": [123456789],  // Your user ID
      "requireMention": true  // Must @mention bot in groups
    }
  }
}

Why: Prevents bot from processing every message in busy groups, reducing API costs.

Rotate Webhook Secret Monthly

# Generate new secret
NEW_SECRET=$(openssl rand -hex 32)

# Update config and Nginx
sed -i "s/webhookSecret.*/webhookSecret\": \"$NEW_SECRET\",/" ~/.openclaw/config.json
sed -i "s/X-Telegram-Bot-Api-Secret-Token.*/X-Telegram-Bot-Api-Secret-Token != \"$NEW_SECRET\"/" /etc/nginx/sites-available/openclaw

# Reload services
sudo systemctl reload nginx
openclaw gateway restart

# Update Telegram
curl -X POST "https://api.telegram.org/bot<TOKEN>/setWebhook" \
  -d "url=https://yourdomain.com/webhook/telegram" \
  -d "secret_token=$NEW_SECRET"

What You Learned

  • Webhooks reduce message latency from seconds to milliseconds
  • Webhook secrets prevent unauthorized POST requests
  • Reverse proxies provide HTTPS without modifying OpenClaw
  • Pairing codes ensure only authorized users can message your bot

Limitation: Webhooks require a public endpoint—if your IP changes frequently, use a dynamic DNS service or stick with polling.


Troubleshooting

Webhook Not Receiving Messages

# Check if Telegram can reach your endpoint
curl -v https://yourdomain.com/webhook/telegram

# Should return 405 Method Not Allowed (GET not supported)
# If timeout/connection refused, check firewall:
sudo ufw allow 443/tcp

Bot Responds Twice to Same Message

OpenClaw is running both polling and webhook. Disable polling in config:

{
  "channels": {
    "telegram": {
      "polling": false,  // Add this line
      "webhookUrl": "https://yourdomain.com/webhook/telegram"
    }
  }
}

Certificate Errors in Logs

Telegram rejects self-signed certificates. Get a free Let's Encrypt cert:

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d yourdomain.com

Tested on OpenClaw 0.x (Feb 2026), Telegram Bot API 7.x, Ubuntu 24.04, Nginx 1.24