Skip to content

Settings — Hooks & Webhooks

This page is the bidirectional automation surface: inbound webhooks push events into Sublarr (e.g. “Sonarr just imported episode X — start searching”), and outbound hooks push events out (e.g. “Sublarr just downloaded a subtitle — tell my custom CMS”).

The webhook receiver lives at /api/v1/webhooks/<source>. Each enabled source has its own URL and HMAC secret:

SourceURL pathWhen the source fires
Sonarr/api/v1/webhooks/sonarrNew episode imported, episode upgraded, series deleted.
Radarr/api/v1/webhooks/radarrNew movie imported, movie upgraded, movie deleted.
Custom JSON/api/v1/webhooks/customAny system you control. Schema documented below.
FieldEffect
EnabledSource toggle.
URLRead-only; copy into the source system’s connection settings.
SecretRequired HMAC secret. The source signs payloads with it; Sublarr verifies.
Auto-translate on importQueue a translation job as soon as the inbound webhook fires.
TestSends a sample payload through the receiver path so you see if it would have worked.

In the *arr UI:

  1. Settings → Connect → +Webhook.
  2. Name: Sublarr.
  3. On Grab / On Import / On Upgrade — select per your needs.
  4. URL: paste from this page.
  5. Method: POST.
  6. Headers: add X-Webhook-Secret: <secret-from-this-page>.
  7. Test → Sublarr should respond OK.
  8. Save.

Send any system’s events to /api/v1/webhooks/custom with the body:

{
"event": "media_imported",
"series_title": "...",
"season": 1,
"episode": 1,
"file_path": "/media/...",
"metadata": { "any": "additional fields" }
}

Required fields: event, file_path. Other fields are optional and used when present.

When something interesting happens inside Sublarr, an outbound hook fires HTTP POST to a configured URL. Useful for integrating with custom dashboards, in-house metadata systems, or just centralised logging.

FieldEffect
LabelDisplay name.
URLWhere Sublarr POSTs.
MethodPOST (default) or PUT.
HeadersCustom headers (e.g. Authorization: Bearer ...).
EventsWhich event types fire this hook.
RetryOn failure: none / 3x exponential / 10x linear.
Timeout (s)Request timeout.
TestSends a sample payload immediately.
{
"event": "subtitle_downloaded",
"timestamp": "2026-05-05T18:42:11.123Z",
"subsystem": "search",
"data": {
"series_title": "Frieren",
"season": 1,
"episode": 7,
"language": "de",
"provider": "jimaku",
"score": 7.2,
"file_path": "/media/anime/Frieren/Season 01/E07.de.srt"
},
"instance_id": "<sublarr-uuid>"
}

The data block varies per event type — full schema lives in Settings → System → Diagnostics → Hook payloads.

EventFires when
subtitle_downloadedA subtitle is written to disk.
subtitle_upgradedAn existing subtitle was replaced by a higher-scoring one.
translation_completedA translation job finishes.
translation_failedA translation job ends in failure.
search_failedAll providers exhausted with no match.
extract_completedAn embedded subtitle was extracted from a container.
cleanup_finishedA cleanup pass completed.
scheduler_job_failedA scheduled job failed three times in a row.
library_scan_finishedA library scan completed.

Sublarr uses two patterns for outbound auth:

PatternSetup
Bearer tokenAdd Authorization: Bearer <token> to the hook’s Headers field.
HMAC signingWhen the receiver expects a signature, paste the shared secret into Hook secret; Sublarr signs the body with X-Sublarr-Signature: sha256=<hex>.

Every outbound hook firing writes to history:

ColumnEffect
TimestampWhen fired.
HookWhich hook.
EventThe event type.
Status200 / 4xx / 5xx / timeout.
LatencyRound-trip time.
Body excerptFirst 1 KB of the request body.
Response excerptFirst 1 KB of the response body.

Use the history table when debugging “why didn’t my downstream get the event?” — the response body usually contains the upstream’s rejection reason.

SettingDefaultEffect
Max concurrent hook firings4Per-Sublarr-instance cap.
Default retry policy3x exponentialOverride per-hook.
Retry backoff base (s)5First retry waits this; doubles each subsequent.

If all retries fail, the hook firing is dropped and a hook_failed log line is written. A failed firing does not block the originating event from being processed.