Get downtime alerts in Telegram
- integrations
- webhook
- telegram
Can I point a YoPingMe webhook straight at Telegram?
No. Telegram's Bot API expects a sendMessage call with a chat_id and
text of its own shape, and it ignores anything else you POST at it.
YoPingMe's webhook channel sends one fixed JSON payload (documented in
the Discord recipe, the same
contract for every receiver). The bridge is the same pattern as the
Discord relay: a Worker of about 25 lines that reshapes the alert into a
Telegram message and forwards it.
You need: a Telegram account, a free Cloudflare account, and a YoPingMe monitor.
Step 1: create the bot and get its token
Message @BotFather in Telegram, send /newbot, and follow the two
prompts (a display name, then a username ending in bot). BotFather
replies with the bot's API token. Treat the token as a secret - anyone
who has it can send messages as your bot.
Step 2: get your chat id
The bot needs somewhere to send alerts: a private chat with you, or a group.
- Private chat: open a chat with your new bot and send it any message (bots cannot message you first).
- Group: add the bot to the group, then send any message in it.
Then read the chat id from the bot's update queue:
curl -s "https://api.telegram.org/bot<TOKEN>/getUpdates"
In the JSON reply, result[0].message.chat.id is the value you want. A
private chat id is a positive number; a group id is negative, minus sign
included.
Step 3: create the relay Worker
In the Cloudflare dashboard, create a new Worker (Workers and Pages, then Create). Replace its code with:
export default {
async fetch(request, env) {
if (request.method !== 'POST') {
return new Response('expected POST', { status: 405 });
}
const alert = JSON.parse(await request.text());
const icon = { down: '🔴', up: '🟢', still_down: '🟡' }[alert.event] ?? '🔵';
const label = { down: 'Down', up: 'Recovered', still_down: 'Still down' }[alert.event] ?? alert.event;
const lines = [
`${icon} ${label}: ${alert.monitor}`,
alert.target,
alert.cause ?? '',
].filter(Boolean);
const tg = await fetch(`https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ chat_id: env.TELEGRAM_CHAT_ID, text: lines.join('\n') }),
});
// A non-2xx answer makes YoPingMe retry, so a Telegram hiccup is
// covered by the same retry schedule as everything else.
return new Response(null, { status: tg.ok ? 200 : 502 });
},
};
The message is deliberately plain text, no parse_mode: Telegram's
Markdown and HTML modes reject messages when a monitor name or cause
string happens to contain a character they treat as markup, and a
dropped alert is a bad trade for bold text.
This recipe uses Cloudflare Workers for the same reason the Discord one does: the free tier (100,000 requests a day, checked 2026-08-07) will not notice your alert volume.
Step 4: set the Worker's secrets
In the Worker's settings, add both as secrets (not plaintext variables):
TELEGRAM_BOT_TOKEN: the token from step 1.TELEGRAM_CHAT_ID: the id from step 2.
With the wrangler CLI instead: wrangler secret put TELEGRAM_BOT_TOKEN
and wrangler secret put TELEGRAM_CHAT_ID.
Step 5: add the channel in YoPingMe
In the YoPingMe dashboard, add an alert channel of type webhook. The URL is your Worker's URL. Attach the channel to your monitors.
As with the Discord relay, the Worker's URL is the credential: there is no shared secret between YoPingMe and the relay, so anyone who has the URL can make your bot post. Keep it private, and rotate it by creating a new Worker (new name, new URL) if it leaks - the Discord recipe spells out the steps.
Step 6: send a test alert
Simulate what YoPingMe sends:
WORKER_URL='https://your-relay.example.workers.dev'
BODY='{"event":"down","idempotency_key":"test-1","incident_id":"inc-test","monitor":"my site","target":"https://example.com","cause":"HTTP 500","sequence_at":"2026-08-08T12:00:00Z"}'
curl -sS -X POST "$WORKER_URL" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: test-1' \
--data "$BODY"
A "🔴 Down: my site" message should arrive in the chat.
Delivery guarantees
The full webhook contract - fields, headers, signature - is documented in
the Discord recipe. The
short version: 10 second timeout, up to 5 attempts over about 10 minutes
of doubling backoff, at-least-once delivery, and duplicates carry the
same idempotency_key. The relay forwards duplicates as-is; Telegram
showing the same alert twice during a retry storm is the honest signal
that delivery was rough, not a bug worth engineering away.