-
Notifications
You must be signed in to change notification settings - Fork 17
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.
| 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.
"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. |
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.
| 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.
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}}.
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.
{
"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
}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
Repository · Releases · Issues · Security policy · Apache-2.0
Getting started
Streaming
Integrations
Operations
Internals
Help