Skip to content

Push Alerts to Telegram via RPC ​

1. Overview ​

ThinkLink (TKL) RPC can call external HTTP endpoints (see RPC Model §1.3.2 Type 4) and forward device alerts to Telegram in real time. This note shows how to create a Telegram Bot and send messages to a chat, channel, or group from an RPC.

2. Prerequisites ​

2.1 Create a Telegram Bot ​

  1. In Telegram, search for @BotFather and send /newbot
  2. Follow the prompts to set the bot's display name and username (must end with bot)
  3. BotFather returns a Bot Token that looks like:
    123456789:AAEhBPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

2.2 Get the Chat ID ​

  1. Add the bot to the target group/channel (for channels, set the bot as admin)
  2. Send any message in the target chat
  3. Open https://api.telegram.org/bot<TOKEN>/getUpdates in a browser and find the chat.id field in the JSON response
  4. Group IDs are usually negative (e.g. -1001234567890); personal chat IDs are positive

2.3 Protect the Bot Token (Required Reading) ​

⚠️ Security notice: The Bot Token is equivalent to full control of the bot — anyone holding it can forge every message the bot sends, read all messages in the bot's groups (if Privacy Mode is off), and remove the bot.

Follow these rules:

  • Do not hard-code the Bot Token into scripts, config files, or screenshots, and never commit it to public repositories (GitHub's secret scanner automatically detects leaked Telegram tokens)
  • Recommended: Store the token in the device's (or asset's) server_attrs and reference it via device.server_attrs.tg_token
  • If you suspect a leak, immediately send /revoke to @BotFather to invalidate the old token and generate a new one
  • Keep the bot's Privacy Mode enabled (default) so it cannot read unrelated group messages
  • Use different bots for different environments (prod / staging / internal) to limit blast radius
  • If the bot is push-only, keep Group Privacy enabled in BotFather → Bot Settings

3. Calling Telegram from an RPC ​

3.1 Store Credentials in server_attrs ​

In Operations → Device Management → Device Detail → Attributes, add to server_attrs:

json
{
    "tg_token": "123456789:AAEhBPxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "tg_chat_id": "-1001234567890"
}

3.2 RPC Script: Markdown Message ​

Telegram supports Markdown and MarkdownV2. The example below uses MarkdownV2 (more robust, but requires escaping special characters):

javascript
function rpc_script({ device, params, alarms, logger }) {
    let token   = device.server_attrs?.tg_token;
    let chatId  = device.server_attrs?.tg_chat_id;
    if (!token || !chatId) {
        logger.error("telegram credentials not configured", { eui: device.eui });
        return null;
    }

    // MarkdownV2 reserved characters: _ * [ ] ( ) ~ ` > # + - = | { } . !
    let esc = (s) => String(s ?? "").replace(/([_*\[\]()~`>#+\-=|{}.!])/g, "\\$1");

    let text = [
        `*🚨 Device Alert*`,
        ``,
        `*Device:* ${esc(device.name)}`,
        `*EUI:* \`${esc(device.eui)}\``,
        `*Level:* ${esc((params.level || "").toUpperCase())}`,
        `*Description:* ${esc(params.desc || "n/a")}`,
        `*Time:* ${esc(new Date().toISOString())}`
    ].join("\n");

    return [
        {
            sleepTimeMs: 0,
            type: "axios",
            dnMsg: {
                method: "POST",
                url: `https://api.telegram.org/bot${token}/sendMessage`,
                headers: { "Content-Type": "application/json" },
                data: {
                    chat_id: chatId,
                    text: text,
                    parse_mode: "MarkdownV2",
                    disable_web_page_preview: true
                },
                timeout: 10000
            }
        }
    ];
}

💡 The TKL server must be able to reach api.telegram.org. If direct access is not available in your network environment, configure a proxy to forward the requests.

3.3 RPC Script: Plain Text Message ​

javascript
function rpc_script({ device, params, alarms, logger }) {
    let token  = device.server_attrs?.tg_token;
    let chatId = device.server_attrs?.tg_chat_id;
    if (!token || !chatId) return null;

    return [
        {
            sleepTimeMs: 0,
            type: "axios",
            dnMsg: {
                method: "POST",
                url: `https://api.telegram.org/bot${token}/sendMessage`,
                headers: { "Content-Type": "application/json" },
                data: {
                    chat_id: chatId,
                    text: params.content || `${device.name} alert`
                },
                timeout: 10000
            }
        }
    ];
}

4. RPC Parameter Configuration ​

Attr NameTypeAliasDescription
contentstringMessage contentUsed in plain-text mode
levelstringAlert levellow / mid / high / urgent
descstringAlert descriptionMarkdown-mode body text

5. Wiring into the Alert Flow ​

See WeCom AN §5 for the trigger script example — just change method to the name of this RPC.

6. Troubleshooting ​

SymptomLikely Cause
UnauthorizedWrong or revoked Bot Token
chat not foundWrong Chat ID; bot not yet in the target group; channel did not promote the bot to admin
Bad Request: can't parse entitiesUnescaped special characters in MarkdownV2
Request timeoutTKL server cannot reach api.telegram.org; increase timeout to 10000+ ms
Rate limitMax 1 message per second per chat; max 30 messages per second across all chats

7. Notes ​

  • Group chat IDs are negative — do not convert them to positive, or messages will go to a private chat with someone else
  • Do not put the Bot Token itself in messages (e.g. don't dump full request bodies or stack traces)
  • With MarkdownV2, escape every piece of dynamic content (device names, descriptions, etc.)
  • For critical alerts, configure multiple notification channels (e.g. Telegram + email) so network issues do not silence alerts