-
Notifications
You must be signed in to change notification settings - Fork 0
Webhooks
CHUB can react to Sonarr, Radarr, and Tautulli events so poster rename and cleanup jobs fire the moment a new item arrives, instead of waiting for the next scheduled run. Every webhook URL is under /api/webhooks/*.
Webhook authentication is optional and off by default. If you set general.webhook_secret in config.yml (or via Settings → General in the UI), every inbound request has to prove it knows the secret:
- Preferred:
X-Webhook-Secret: <secret>HTTP header - Fallback for services that can't send custom headers:
?secret=<secret>query parameter
A wrong or missing secret returns 401. If webhook_secret is empty, webhooks run unauthenticated — fine on a trusted LAN, but don't expose unauthenticated webhook URLs to the open internet.
Who calls it: Sonarr / Radarr / Tautulli on a media event. Sonarr and Radarr are the primary callers; Tautulli is useful if you want one trigger source that also covers Plex-side adds Sonarr/Radarr don't see.
What CHUB does: validates the payload, deduplicates against the persistent webhook_cache (600-second rolling TTL keyed on the media identity hash — survives restarts, so retries from a Sonarr/Radarr instance that timed out earlier still get coalesced), then enqueues a poster-processing job scoped to the single item in the payload. The job goes through the same pipeline a scheduled run uses: rename → border replacer (if enabled) → Plex upload.
Accepted event types: only events that correspond to a new on-disk file are processed. Anything else gets a 200 ack and is dropped.
| Event | Sonarr trigger label | Radarr trigger label | Processed? |
|---|---|---|---|
Download |
On Import / On Upgrade | On Import / On Upgrade | ✅ |
EpisodeFileImported |
On Import (v4+) | — | ✅ |
MovieFileImported |
— | On Import (v5+) | ✅ |
SeriesAdd |
On Series Add | — | ✅ |
MovieAdded |
— | On Movie Added | ✅ |
Test |
(Test button) | (Test button) | ✅ acked, no job |
Grab |
On Grab | On Grab | 🚫 ignored — file isn't on disk yet |
Rename |
On Rename | — | 🚫 ignored |
*FileDelete, *Delete, HealthIssue, ApplicationUpdate, etc. |
On … | On … | 🚫 ignored |
Season-aware import: when a Sonarr Download or EpisodeFileImported payload carries episodes[*].seasonNumber, CHUB extracts it and narrows the rename pass to (show row + matching season row) instead of re-walking every season's assets. One imported episode → one season's posters re-checked.
Returns the current unmatched-assets summary — how many posters don't have a media match. Useful for dashboards and uptime probes.
Enqueues an unmatched_assets run to refresh the report. Anything that can send an HTTP POST can trigger this (cron, Home Assistant, a shortcut on your phone).
Returns the current orphaned-poster count.
Enqueues a poster_cleanarr run.
- Open Sonarr → Settings → Connect → + → Webhook.
-
URL:
http://<chub-host>:8000/api/webhooks/poster/add -
Method:
POST - Notification Triggers: check On Import, On Upgrade, and On Series Add. Leave the rest unchecked — CHUB ignores them.
-
Headers: if you set a webhook secret, add
X-Webhook-Secret: <your secret>here. - Click Test — Sonarr fires a
Testevent; CHUB returns200and records the origin under Settings → Webhooks → Recent origins. - Click Save.
- Open Radarr → Settings → Connect → + → Webhook.
-
URL:
http://<chub-host>:8000/api/webhooks/poster/add -
Method:
POST - Notification Triggers: check On Import, On Upgrade, and On Movie Added. Leave the rest unchecked.
-
Headers: same
X-Webhook-Secretas Sonarr if you set a secret. - Click Test then Save.
Tip: CHUB's Settings → Webhooks page generates ready-to-paste URLs with the secret already applied.
- Settings → Notification Agents → Add a new notification agent → Webhook.
-
URL:
http://<chub-host>:8000/api/webhooks/poster/add - Triggers: Recently Added is usually enough.
- Data format: JSON. Leave the template blank unless you know what you're overriding.
By default CHUB hashes every poster file on disk and skips the upload if the hash matches what was last pushed to Plex — so a webhook for an unchanged poster is a no-op. If a Plex instance has been wiped or you're actively re-curating a library and want every webhook to re-push regardless, set webhook_force_reupload: true on the originating *arr instance:
instances:
sonarr:
main:
url: http://sonarr:8989
api: ...
webhook_force_reupload: true # webhooks from this Sonarr always re-push
radarr:
main:
url: http://radarr:7878
api: ...
# webhook_force_reupload omitted → defaults to falseThe flag only affects webhook-triggered uploads from that instance. Scheduled and manual runs still respect the hash-skip.
After enqueuing the job, CHUB polls each configured Plex section's recently-added list before pushing posters — Plex's library scan can lag several minutes behind a Sonarr/Radarr import. Defaults give a ~5.5-minute search window:
general:
webhook_initial_delay: 30 # seconds to wait before the first Plex check
webhook_retry_delay: 30 # seconds between retries
webhook_max_retries: 10 # total attemptsIf the item still isn't found after every retry, the upload step is skipped for this run; the next scheduled rename will pick it up.
Every webhook-created job records who called it — the source host, the endpoint hit, the event type, and the user agent. Settings → Webhooks → Recent origins shows a rollup of the last 7 days: useful for spotting a noisy integration or catching an unexpected caller.
If CHUB enqueues a job but the underlying module later fails, the webhook doesn't retry the inbound call — the job lives in the normal queue and follows its own retry rules. If the inbound webhook call itself errors (for instance, CHUB is mid-restart), Sonarr/Radarr will retry per their own settings, and the persistent webhook_cache keeps duplicate retries from re-firing the pipeline within the 600-second TTL.
-
401 Unauthorized— yourwebhook_secretis set but the caller isn't sending the header or?secret=. Copy the URL from Settings → Webhooks to get a version with the secret already applied. -
404 Not Found— path typo. Every endpoint is under/api/webhooks/*, not/webhook/*. -
200but nothing happens — three possibilities:- The event type isn't on the allow-list (e.g. you checked On Grab in Sonarr — files aren't on disk yet, so CHUB silently 200s).
- The same item fired within the 600-second dedup window. Look for
Duplicate webhook debouncedat debug level. - The job ran but failed downstream. Check Settings → Jobs, filter by module and status.
-
Sonarr says "Test connection failed" — almost always a network issue: Sonarr can't reach the CHUB host/port. Verify from inside Sonarr's container:
curl -I http://chub:8000/api/health. -
A new download didn't get its poster pushed to Plex — the
wait_for_plex_availabilityretry budget (5.5 min by default) may have run out before Plex finished scanning. Either bumpwebhook_max_retriesor wait for the next scheduled rename.
See Troubleshooting for more.