Skip to content

Webhooks

DatanoiseTV edited this page Jun 18, 2026 · 1 revision

Webhooks

Outbound HTTP notifications for stream and AutoDJ events, with templated bodies so you can match whatever shape the receiver wants. Manage from Admin → Webhooks or the JSON API at /api/webhooks (super-admin only).

SSRF guard: webhook URLs are validated against the same rules as relays — loopback, private (RFC 1918), and link-local addresses are rejected. See Security.

Events

Event Fires when Payload includes
now_playing A new track starts on an AutoDJ mount mount, name, artist, title, album, file, format, bitrate, duration_seconds
source_connect An external source connects mount
source_disconnect An external source disconnects mount
metadata_update Mount metadata (title/artist/song) changes mount, song fields
security_lockout An IP is locked out for repeated auth failures IP, reason

A webhook subscribes to one or more events via its events list.

Configuration

"webhooks": [
    {
        "name": "Discord — #now-playing",
        "url": "https://discord.com/api/webhooks/<id>/<token>",
        "method": "POST",
        "content_type": "application/json",
        "headers": { "X-Source": "tinyice" },
        "events": ["now_playing"],
        "body_template": "{\"content\": \"Now playing: {{.Artist}} - {{.Title}}\"}",
        "enabled": true
    }
]
Field Default Notes
id auto Stable handle (assigned on load if missing).
name Label in the UI.
url Target. SSRF-validated.
method POST Any HTTP method.
content_type application/json Request Content-Type.
headers Extra request headers (auth tokens, routing keys).
events Which events trigger this webhook.
body_template Go text/template. Empty = legacy JSON envelope.
enabled Per-webhook toggle.

Body templates

Leave body_template empty to send the legacy JSON envelope ({event, timestamp, hostname, data}) — existing receivers keep working unchanged. Fill it in to render any shape with Go's text/template.

For GET / HEAD webhooks the rendered body is appended to the URL as a query string instead of sent as a request body — that's how the TuneIn AIR Playing.ashx preset works from a single template.

Always-available variables

Variable Example
{{.Event}} now_playing
{{.Timestamp}} 2026-05-04T19:30:00Z
{{.UnixTimestamp}} 1809974400
{{.Date}} · {{.Time}} 2026-05-04 · 19:30:00
{{.Hostname}} · {{.BaseURL}} · {{.Version}} from config

When the payload carries a mount, the dispatcher derives {{.MountURL}} (public listen URL) and {{.PlayerURL}} (embedded player) from base_url. Use {{if .MountURL}}…{{end}} to no-op gracefully when base_url isn't set.

Payload variables and helpers

Every key from the event payload is promoted to the top level, in both snake_case and a CamelCase alias — {{.duration_seconds}} and {{.DurationSeconds}} both work; likewise {{.Artist}}, {{.Title}}, {{.Mount}}.

Helper functions: urlencode, json, lower, upper. Example: {{.Artist | urlencode}}.

Presets

The editor's Load preset dropdown fills method, headers, and body for: Discord, Slack, Mattermost, Microsoft Teams (MessageCard), Telegram bot sendMessage, ntfy.sh, Pushover, TuneIn AIR Playing.ashx, a generic JSON envelope, and webhook.site (echo, for debugging templates). Loading a preset leaves your URL field alone if you've already typed one.

Each row has a Test button that fires a sample payload so you can validate the template before going live.

Example: Discord "now playing"

{
  "name": "Discord — #now-playing",
  "url": "https://discord.com/api/webhooks/<channel-id>/<token>",
  "method": "POST",
  "events": ["now_playing"],
  "body_template": "{\"username\":\"TinyIce\",\"content\":\":musical_note: **{{.Mount}}** — {{.Artist}} – {{.Title}}{{if .MountURL}} — [Listen]({{.MountURL}}){{end}}\"}",
  "enabled": true
}

Prefer a local script?

For track-start specifically, the AutoDJ on_play_command hook runs a shell command with the track metadata in environment variables — no HTTP endpoint required. Webhook panics in user-supplied subscribers are contained by recover() so a bad receiver can't crash the server.


Next: HTTP API · Observability · Authentication and Users

Clone this wiki locally