-
Notifications
You must be signed in to change notification settings - Fork 68
Notifications
Bindery fires a webhook when something interesting happens: a release is grabbed, a book is imported, a download fails, the service itself goes unhealthy, or a book upgrades to a preferred format. Notifications are generic HTTP webhooks — there are no built-in adapters for Slack/Discord/ntfy/etc. The page below shows how to wire each of those up to the generic webhook.
| Event | Triggered when… |
|---|---|
grabbed |
A release was sent to SABnzbd or qBittorrent |
bookImported |
A downloaded file was successfully moved/renamed into the library |
upgrade |
An already-imported book was replaced with a higher-ranked format |
downloadFailed |
The download client reported a terminal failure |
health |
A background health check flipped to unhealthy (indexer unreachable, disk full, etc.) |
Each notification row has a flag per event (onGrab, onImport, onUpgrade, onFailure, onHealth), so one webhook endpoint can be subscribed to any subset.
All notifications POST a JSON body. The minimum shape is:
{ "eventType": "grabbed", "message": "…" }Per-event payloads include the relevant book / release context. A grabbed event, for example, also includes the book title, author, release title, and indexer name. The easiest way to see the exact shape for your version is to create a notification pointing at a request-bin (https://webhook.site/) and fire the Test button in the UI.
The request always uses:
Content-Type: application/jsonUser-Agent: Bindery/1.0- HTTP method — configurable per notification (defaults to
POST) - Any headers you add as the
HeadersJSON object (e.g.{"Authorization":"Bearer xyz"})
Responses in the 2xx range are treated as success. Anything else is logged as a failed webhook but does not retry — integrations that require at-least-once delivery should queue on their own end.
ntfy accepts the Bindery JSON body directly — just POST to your topic URL.
-
URL:
https://ntfy.sh/your-topic(or self-hosted) -
Method:
POST -
Headers:
{"Title":"Bindery","Priority":"default","Tags":"books"}
For per-event titles, spin up one notification per event type so the Title header reflects the event.
Slack's incoming webhooks expect {"text": "..."}. Bindery sends a rich JSON body instead, so Slack will fall back to a best-effort render. For a cleaner message, send to an intermediary (like Huginn, n8n, or a one-line AWS Lambda) that reshapes the payload.
- URL: your Slack app's incoming-webhook URL
-
Method:
POST -
Headers:
{}
Discord's webhook API accepts {"content": "..."} or {"embeds": [...]}. Same caveat as Slack — Bindery's payload is not Discord-shaped, so either accept the raw-JSON fallback or run it through a reshaper.
-
URL:
https://discord.com/api/webhooks/…/… -
Method:
POST
Home Assistant's http integration exposes a webhook trigger that accepts any JSON — this is the cleanest target.
-
URL:
https://homeassistant.local:8123/api/webhook/<webhook_id> -
Method:
POST -
Headers:
{} - Reference the payload inside your automation as
{{ trigger.json.eventType }},{{ trigger.json.message }}, etc.
Apprise runs as a tiny HTTP service and speaks to ~100 providers (Telegram, Gotify, Mattermost, Pushover…). Bindery → Apprise → provider is the easiest way to get rich, per-provider formatting.
-
URL:
http://apprise:8000/notify/<config_key> -
Method:
POST -
Headers:
{}
Apprise expects {"title":"…","body":"…","type":"info"}. Like Slack/Discord, you'll want a thin shim between Bindery and Apprise — or raise #95 if you'd like a built-in Apprise adapter.
Webhook URLs are validated against internal/httpsec.ValidateOutboundURL with strict policy by default:
- Loopback (
127.0.0.0/8,::1) — blocked - Link-local (
169.254.0.0/16,fe80::/10) — blocked - Cloud-metadata (
169.254.169.254,metadata.google.internal) — blocked - RFC1918 (
10/8,172.16/12,192.168/16) — blocked
If your ntfy / Home Assistant / Apprise instance is on the same LAN, flip to LAN policy with:
BINDERY_NOTIFICATIONS_ALLOW_PRIVATE=1
The flag only loosens notifications — indexer and download-client URLs already default to LAN policy since homelabs almost always put Sonarr-adjacent services on RFC1918 space.
See Security for the full SSRF story.
# List
curl -H "X-Api-Key: $KEY" http://bindery:8787/api/v1/notification
# Create
curl -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
-X POST http://bindery:8787/api/v1/notification \
-d '{
"name": "ntfy-books",
"type": "webhook",
"url": "https://ntfy.sh/my-books-topic",
"method": "POST",
"headers": "{\"Title\":\"Bindery\",\"Tags\":\"books\"}",
"onGrab": true,
"onImport": true,
"onFailure": true,
"onHealth": true,
"onUpgrade": false,
"enabled": true
}'- Security — full SSRF policy matrix.
Getting started
Setup guides
How-to guides — proxy auth (v1.0)
How-to guides — OIDC (v1.0)
- Google Sign-In
- GitHub OAuth via Dex
- Authelia as OIDC provider
- Authentik
- Keycloak
- Rotate OIDC client secrets
- Recover from broken OIDC
How-to guides — multi-user (v1.0)
Reference
Contributing