Webhooks
Webhooks push Cortex domain events to an HTTP endpoint you host. Delivery is reliable: events are persisted before they’re sent, retried with backoff if your endpoint is down, and signed so you can verify they really came from Cortex.
Creating a subscription
Subscribe to the events you care about (exact names, domain.* wildcards, or * for
everything) and provide a secret used to sign deliveries:
Managing subscriptions with an API key requires the
webhooks scope.
You can also configure how Cortex authenticates to your endpoint — authType of
none (default), api_key (with apiKey and an optional apiKeyHeader, default
X-API-Key), basic_auth (basicAuthUsername / basicAuthPassword) or custom_headers
(customHeaders) — on top of the signature.
What a delivery looks like
Each delivery is a POST with a JSON body that wraps the
domain event:
The event data is at body.payload.payload.data — the outer payload is the domain event,
the inner one its action-typed payload.
Verifying signatures
Every delivery is signed with HMAC-SHA256 over the raw request body, keyed with your
subscription secret. The signature arrives in the X-Odin-Signature header as
sha256=<hex digest>. Verify it before trusting the payload — and compute it over the exact
bytes you received, before any JSON parsing:
Always compare with a constant-time function like timingSafeEqual, never ===.
Reliable delivery (the outbox)
Cortex writes each matching event to a durable outbox before delivering it, so an endpoint that’s temporarily down never loses events:
- On
2xx, the delivery is marked delivered. Respond within 10 seconds — a slower response counts as a failed attempt. - On error or non-
2xx, it’s retried with exponential backoff (after roughly 1 minute, 5 minutes, 30 minutes, 2 hours and 24 hours) until it succeeds or the attempt limit is reached; then it is marked failed. - Each attempt is recorded so you can audit delivery history, and every status change emits a
webhook.delivery.updatedevent you can subscribe to for alerting.
Because failed deliveries are retried, your endpoint may receive the same event more than
once. Deduplicate by the event id (body.payload.id) and make handling idempotent.
Inspecting deliveries
List the delivery queue (pending / delivered / failed attempts) to debug integration issues:
Webhooks vs SSE vs functions
All three are driven by the same domain-event catalog:
| Surface | Best for | Delivery |
|---|---|---|
| Webhooks | Server-to-server integrations with your backend | Durable, retried, signed |
| SSE | Live dashboards / UI | Real-time stream, no replay |
| Functions | Custom logic you don’t want to host | Durable (same outbox path) |