Webhooks

Any HTTP POST becomes an SMS

One URL, no integration code

Create a webhook, get a secret URL, paste it into any tool that can send an HTTP request. Uptime Kuma, Grafana, Prometheus Alertmanager, GitHub Actions, Zabbix, cron jobs, your own scripts — if it can POST, it can text you.

How it stays safe

Recipients are fixed when you create the webhook

The incoming payload can only influence what the message says — never who receives it. Phone numbers are never read from the request body.

This is deliberate. A webhook URL tends to end up in config files, dashboards and screenshots. If the payload could choose the recipient, anyone who saw the URL could send messages to any number at your expense — including premium-rate numbers.

Hourly cap

Default 20/hour per webhook. An alert storm can't drain your quota or upset your carrier.

IP allowlist

Optionally restrict which sources may trigger it. Exact IPs or CIDR ranges.

Rotatable secret

If a URL leaks, rotate it — the old one stops working immediately.

1. Create a webhook

curl -X POST https://smstunnel.io/api/v1/webhooks \
  -H "Authorization: Bearer YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Server alerts",
    "recipients": ["+40712345678"],
    "maxPerHour": 20
  }'

The response contains your secret URL:

{
  "id": "...",
  "token": "a1b2c3...",
  "url": "/api/v1/webhook/a1b2c3..."
}

Full URL: https://smstunnel.io/api/v1/webhook/<token>

2. Trigger it

curl -X POST https://smstunnel.io/api/v1/webhook/<token> \
  -H "Content-Type: application/json" \
  -d '{"message": "Backup finished successfully"}'

A plain GET works too, for tools that can only ping a URL — the query string becomes the payload: …/webhook/<token>?message=Disk+almost+full

3. What the SMS says

Automatic (no configuration)

Common formats are recognised out of the box, so most tools work immediately:

  • Uptime Kuma — monitor name, up/down status and message
  • Prometheus Alertmanager / Grafana — status, alert name and summary
  • Generic — any message, text, title, body or summary field

Custom template

Set messageTemplate and pull any field out of the payload with {{path}}, including array indexes:

"[{{status}}] {{alerts.0.labels.alertname}} on {{alerts.0.labels.instance}}"

Messages are trimmed to 480 characters — alerts should be short, and it keeps one noisy payload from consuming several SMS.

Ready-made setups

Uptime Kuma

Settings → Notifications → Setup Notification

  • Notification Type: Webhook
  • Post URL: https://smstunnel.io/api/v1/webhook/<token>
  • Request Body: Preset - application/json

No template needed — the monitor name and up/down status are detected automatically.

Prometheus Alertmanager

receivers:
  - name: sms
    webhook_configs:
      - url: https://smstunnel.io/api/v1/webhook/<token>

Grafana

Alerting → Contact points → Add contact point → Webhook, then paste the URL. Grafana's unified alerting payload is recognised automatically.

GitHub Actions

- name: Notify on failure
  if: failure()
  run: |
    curl -X POST "${{ secrets.SMS_WEBHOOK }}" \
      -H "Content-Type: application/json" \
      -d '{"message":"Build failed on ${{ github.repository }}"}'

Cron / any script

0 3 * * * /opt/backup.sh || curl -s -X POST \
  https://smstunnel.io/api/v1/webhook/<token> \
  -H 'Content-Type: application/json' \
  -d '{"message":"Nightly backup FAILED"}'

Managing webhooks

Endpoint Purpose
GET /api/v1/webhooksList, with usage counters
PATCH /api/v1/webhooks/:idChange recipients, template, limits
POST /api/v1/webhooks/:id/rotateIssue a new secret URL
DELETE /api/v1/webhooks/:idRemove it

All management endpoints require your account JWT.

Responsible use

Webhooks are meant for alerting and transactional notifications. Sending unsolicited bulk messages from a consumer SIM generally breaches mobile carrier terms — keep volumes low and make sure your usage complies with local regulations.

Prefer a visual workflow?

The n8n node gives you the same power with a drag-and-drop editor.

See the n8n integration