Send server alerts to Telegram with one curl command
To send a server alert to Telegram with curl, POST the alert text to your push.tg address: curl -d "Backup failed" https://push.tg/k3x9q. It arrives in your chat a moment later. No BotFather, no bot token, no chat_id.
Opens @trafficRobot in Telegram. Press Start and your first address arrives in seconds.
Why not just use the Telegram Bot API?
The usual tutorial (Hetzner, Stack Overflow, countless blogs) goes: create a bot with BotFather, copy the token, send it a message, call getUpdates to find your chat_id, then build a sendMessage URL and keep the token secret on every server. It works, but it's five steps and a credential to manage.
With push.tg you skip all of it. Open @trafficRobot, press Start, and you get an address like k3x9q@push.tg. https://push.tg/k3x9q is now your alert endpoint. Create the address inside a group and the whole group gets the alerts.
| push.tg | DIY Telegram bot | Hosted alert APIs | |
|---|---|---|---|
| Steps before first alert | Press Start | BotFather, token, chat_id, URL | Sign up, API key, channel setup |
| Secrets to manage | The address itself | Bot token + chat_id | API key |
| Request | curl -d "text" URL | URL with token and query params | JSON body + auth header |
| Groups | Yes | Yes | Varies |
| Same address receives email | Yes | No | No |
The basics
# simplest form: the raw body is the message
curl -d "Backup finished on $(hostname)" https://push.tg/k3x9q
# recommended in scripts: quiet, fail on errors, never hang
curl -sS --max-time 10 --data-urlencode "data=Backup finished on $(hostname)" https://push.tg/k3x9q
# multiline text, or text containing = and & characters
curl -sS --max-time 10 --data-urlencode "data=$(printf 'Disk report\n%s' "$(df -h /)")" https://push.tg/k3x9q
# pipe a file or command output
df -h / | curl -sS --max-time 10 --data-urlencode "data@-" https://push.tg/k3x9q
Tip: --data-urlencode "data=..." is the safest form. A raw body that contains = or & can be read as form fields. The API replies with a short JSON line, e.g. {"ok":…} or {"error":"no such user"}. Telegram messages are capped at 4096 characters, so send summaries, not full logs.
Copy-paste examples
Cron: alert only when a job fails
Cron runs with a minimal PATH, so use absolute paths.
# crontab -e
0 3 * * * /usr/local/bin/backup.sh || /usr/bin/curl -sS --max-time 10 --data-urlencode "data=Backup FAILED on $(/bin/hostname) at $(/bin/date)" https://push.tg/k3x9q
Inside crontab, % is special. If you need date +%F, escape it as \% or move the logic into a script.
Bash: a reusable notify function with the exit code
#!/usr/bin/env bash
PUSHTG="https://push.tg/k3x9q"
notify() { curl -sS --max-time 10 --data-urlencode "data=$1" "$PUSHTG" >/dev/null || true; }
output=$(/usr/local/bin/sync-data.sh 2>&1); status=$?
if [ "$status" -ne 0 ]; then
notify "sync-data failed on $(hostname) (exit $status):
$(printf '%s\n' "$output" | tail -n 20)"
fi
HTTP health check (no monitoring stack needed)
# */5 * * * * /usr/local/bin/healthcheck.sh
#!/usr/bin/env bash
URL="https://example.com/health"
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 15 "$URL")
if [ "$code" != "200" ]; then
curl -sS --max-time 10 --data-urlencode "data=$URL returned $code" https://push.tg/k3x9q
fi
Python
import requests
def notify(text: str) -> None:
try:
requests.post("https://push.tg/k3x9q", data={"data": text}, timeout=10)
except requests.RequestException:
pass # never let an alert crash the job
notify("Training run finished: val_loss=0.231")
Passing a dict sends form-encoded data=..., which handles any characters. Standard library only: urllib.request.urlopen("https://push.tg/k3x9q", urllib.parse.urlencode({"data": text}).encode(), timeout=10).
GitHub Actions
Store your address prefix (e.g. k3x9q) as a repository secret named PUSHTG_ADDR.
- name: Notify Telegram
if: always()
run: |
curl -sS --max-time 10 \
--data-urlencode "data=${{ github.repository }} ${{ github.workflow }}: ${{ job.status }} (${{ github.ref_name }})" \
"https://push.tg/${{ secrets.PUSHTG_ADDR }}"
Use if: failure() instead of if: always() to hear only about broken builds.
Uptime Kuma and other webhook tools
In Uptime Kuma: Settings → Notifications → Setup Notification → Notification Type: Webhook.
- Post URL:
https://push.tg/k3x9q - Request Body: Custom Body, with the body set to
{{msg}}
Any tool that can POST plain text to a URL works the same way (Grafana contact points, Healthchecks.io webhooks, n8n, Home Assistant rest_command). If a tool can only send email, point it at k3x9q@push.tg, because the same address receives email. That covers NAS boxes, UPS software and older monitoring.
Large JSON payloads with = or & inside may be cut. Prefer a short text template where the tool allows it.
systemd: OnFailure= for any service
# /etc/systemd/system/notify-failure@.service
[Unit]
Description=Send Telegram alert for failed unit %i
[Service]
Type=oneshot
ExecStart=/usr/bin/curl -sS --max-time 10 --data-urlencode "data=Unit %i failed on %H" https://push.tg/k3x9q
# then add to any unit, e.g. /etc/systemd/system/backup.service
[Unit]
OnFailure=notify-failure@%n.service
sudo systemctl daemon-reload
sudo systemctl start notify-failure@test.service # sends a test alert
Node.js
await fetch("https://push.tg/k3x9q", { method: "POST", body: new URLSearchParams({ data: "New signup!" }) });
Good to know
- Treat the address like a password. Anyone who knows it can message you. If it leaks, delete it in the bot and create a new one.
- Each alert is tagged with the address it came through, so separate addresses per server or project keep things readable.
- Best effort. Delivery depends on push.tg and Telegram being reachable. For paging that must never be missed, keep a second channel.
- Free to start. A free allowance covers everyday use, and the bot tells you if you reach it.
FAQ
How do I send a Telegram message with curl?
Get an address from @trafficRobot, then run curl -d "your message" https://push.tg/YOUR_PREFIX. The text arrives in your Telegram chat. For scripts, use curl -sS --max-time 10 --data-urlencode "data=your message" so any characters work.
Do I need a bot token or chat_id?
No. The push.tg address is the only thing you need. There's no BotFather step, no token and no chat_id lookup.
Can I send alerts to a Telegram group?
Yes. Add @trafficRobot to the group and create the address inside it. Everything posted to that address goes to the whole group.
How do I get cron job failures in Telegram?
Append || /usr/bin/curl -sS --max-time 10 --data-urlencode "data=job failed" https://push.tg/YOUR_PREFIX to the cron line. The curl runs only when the job exits with an error. Use absolute paths, since cron has a minimal PATH.
How do I send multiline messages?
Use --data-urlencode "data=..." with real newlines in the value, or pipe text in with --data-urlencode "data@-". Telegram caps messages at 4096 characters.
Is delivery guaranteed?
No. It's best effort: alerts depend on push.tg and Telegram being reachable. For critical paging, keep a second channel as a backup.
Can monitoring tools that only send email use it?
Yes. The same address receives email, so NAS devices, UPS software and older monitoring that only support email alerts can send to YOUR_PREFIX@push.tg.
What happens if my address leaks?
Anyone with the address can send you messages. Delete it in the bot and create a new one, then update your scripts.
Get your alert endpoint in 5 seconds
Free to start, no ads, no sign-up form. All you need is Telegram.
Open @trafficRobot →