Webhook
The webhook notifier sends a JSON POST to any HTTP endpoint: PagerDuty, n8n,
your own server. For Discord, use the
Discord notifier instead, which sends
messages Discord can display.
[notifiers.my-hook]type = "webhook"url = "${WEBHOOK_URL}"
[notifiers.my-hook.headers]Authorization = "Bearer ${WEBHOOK_TOKEN}"Fields
Section titled “Fields”| Key | Required | What it does |
|---|---|---|
url |
yes | The endpoint. Keep it out of the file; see Storing the secret. |
headers |
no | Extra HTTP headers sent with every request, like an auth token. Values can use ${...} too. |
template_path |
no | A Go template file that replaces the built-in JSON body. |
Webhook notifiers don’t accept a my-hook:<target> override.
What the body looks like
Section titled “What the body looks like”Each event is one POST with Content-Type: application/json. The keys are
stable, so you can parse them safely:
{ "kind": "run.failed", "severity": "error", "timestamp": "2025-01-15T02:30:45Z", "task": "backup-postgres", "title": "backup-postgres failed", "message": "Exited with code 1 after 3m 4s.", "trigger": "Scheduled run", "run": { "id": "01JXYZ...", "exit_code": 1, "triggered_by": "cron", "url": "https://runwisp.example.com/tasks/backup-postgres/01JXYZ...", "duration": "3m 4s" }, "output_tail": "Error: connection refused\ndial tcp ...", "reason": "exit 1", "source": "runwisp (bright-falcon)"}run, output_tail, and reason appear only when they apply. Inside run,
url needs external_url, and
duration appears only for runs that have one.
Changing the body
Section titled “Changing the body”Point template_path at your own Go template. Start from the built-in
webhook.tmpl.json.
It gets the whole event and the same helpers as the
Slack template.
What’s rejected
Section titled “What’s rejected”- A missing or empty
url, or one that isn’thttp://orhttps://. - An empty key in
headers.