push.tg logopush.tgOpen in Telegram
curl → Telegram · @trafficRobot

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.

Get my alert endpoint →

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.tgDIY Telegram botHosted alert APIs
Steps before first alertPress StartBotFather, token, chat_id, URLSign up, API key, channel setup
Secrets to manageThe address itselfBot token + chat_idAPI key
Requestcurl -d "text" URLURL with token and query paramsJSON body + auth header
GroupsYesYesVaries
Same address receives emailYesNoNo

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.