POST that Cativa sends to a URL of yours every time an event happens in the tenant (a user signs up, a payment clears, a post is published). Instead of polling the API, Cativa notifies you the moment the event occurs.
Here you’ll find: how to register the listener, the list of events, how to verify the signature, and how to handle retries and duplicates.
One event per listener. Each subscription listens to one event name (e.g.
user_created). To listen to several events, create several listeners, pointing them all at the same URL if you want. Each listener has its own secret.Two ways to subscribe
Via the Console
Visual, no code. Best to configure quickly and reveal the secret on screen.
Via the management API
Programmatic and versionable. Best to provision listeners at scale or through infrastructure as code.
Subscribe via the Console
In the Cativa dashboard, open Console > Webhooks and click Add listener. The flow asks for 3 things:- URL — your app’s public endpoint that will receive the
POST(e.g.https://myapp.com/webhooks/cativa). - Event — the event name you want to listen to (snake_case, e.g.
user_received_badge). - Secret — generated automatically. After you create the listener, open it and click Reveal secret to copy the value (format
whsec_+ 64 hex characters). Only the tenant admin can reveal the secret. Store it safely in your credentials vault.
Subscribe via the management API
The webhook management endpoints live under theadmin/integration/{customerId}/webhooks resource. {customerId} is your tenant’s ID.
- Base URL:
https://apis.cativalab.digital/tenant/api/v2 - Authentication: header
Authorization: Bearer YOUR_API_KEY(the API key starts withcativa_).
1
Create the subscription (and store the secret)
Send a Response:
POST with the EventName and Url. The response returns the Secret once — copy and store it before closing the connection. After that it can’t be retrieved via the API (only revealed in the Console).If you omit
GroupId, the listener fires for the event across the whole tenant. Provide a GroupId to listen to a single group only.2
Receive the POST at your endpoint
Every delivery arrives as a
POST with Content-Type: application/json and the headers X-Cativa-Signature, X-Cativa-Execution-Id, X-Cativa-Automation-Id and X-Cativa-Idempotency-Key (detailed in Delivery headers).3
Verify the HMAC signature
Before trusting the payload, recompute the HMAC-SHA256 with your
Secret and compare it in constant time against the X-Cativa-Signature header. Reject deliveries with a timestamp outside the 5-minute window. Ready-to-use code in Node and Python in the Verifying the HMAC signature section.4
Respond 2xx fast
Respond
200 (any 2xx works) as soon as you validate the signature. Don’t do heavy work inside the request. Queue the processing and answer fast, otherwise the delivery times out and enters a needless retry.5
Deduplicate redeliveries
Delivery is at-least-once. Use the
X-Cativa-Idempotency-Key header (or X-Cativa-Execution-Id) to drop duplicates. Details and code in Idempotency.6
Let Cativa retry failures
If you respond
5xx/408/429 or the connection drops, Cativa retries on its own on the backoff curve. You don’t have to do anything beyond going back to responding 2xx. Details in Retries and permanent failures.Management endpoints
All requireAuthorization: Bearer YOUR_API_KEY and use the base https://apis.cativalab.digital/tenant/api/v2.
List subscriptions
List subscriptions
Update a subscription
Update a subscription
Temporarily disable it or swap the URL without recreating the listener (the secret is preserved):
Remove a subscription
Remove a subscription
Inspect deliveries (logs and executions)
Inspect deliveries (logs and executions)
Logs for a specific subscription:All tenant executions, filtering by failures of one event in the last 24h:
Available events
Use exactly these snake_case names in the
EventName field when subscribing — that’s how Cativa matches.
Verifying the HMAC signature
The signature is what proves the delivery really came from Cativa (and not from someone who found your URL). Always verify before processing. Every delivery ships the header:t— Unix timestamp (seconds) at delivery time.v1— HMAC-SHA256 (hex, lowercase) over the string"<t>.<rawBody>", using the listener’ssecretas the key.
- Parse the header into
tandv1. - Anti-replay — reject the request if
|now - t| > 300seconds (5 minutes is the industry standard). This blocks the replay of an old captured request. - Recompute the HMAC and compare in constant time (
timingSafeEqual/hmac.compare_digest), never with==.
Delivery headers
Retries and permanent failures
If your endpoint doesn’t reply with2xx, Cativa retries on this curve:
X-Cativa-Idempotency-Key and X-Cativa-Execution-Id.
Cativa honors the Retry-After header you return (capped at the next backoff window’s max).
Behavior table by status
The logic: status in the
4xx range (except 408 and 429) means “the request is wrong and retrying won’t help” — typically a client bug, deactivated URL or wrong auth. Status 5xx, 408, 429 and transport errors mean “try again later”.
When all retries fail
If the 7th attempt also fails, the delivery becomes a dead-letter and is recorded in the logs (queryable viaGET .../webhooks/{webhookId}/logs and GET .../executions). Monitor your endpoint’s uptime on your own side, and if you suspect missed events, check the logs or open a ticket at dev@cativa.digital.
Idempotency
Delivery is at-least-once. The same event can arrive more than once (retries after a timeout, connection loss while replying). You have to detect duplicates on your side. The canonical key is theX-Cativa-Idempotency-Key header: it’s deterministic per delivery and stays the same across all retries (the X-Cativa-Execution-Id also works). Save that ID in the same transaction as your business logic:
Best practices
Respond fast, process later
Respond fast, process later
Validate the signature, enqueue the payload (queue, outbox table, topic) and respond
2xx right away. Heavy processing inside the request times out and generates needless retries.Always verify the signature
Always verify the signature
Never act on an unverified payload. Your URL can leak (logs, proxies) and anyone can
POST to it. The HMAC is what separates a legitimate delivery from a forged one.Be idempotent
Be idempotent
Record the
X-Cativa-Idempotency-Key and drop redeliveries. Assume every event can arrive twice.Set timeouts on your side
Set timeouts on your side
External calls inside the handler (CRM, email) should have short timeouts. If a third-party provider hangs, you hang the response and it becomes a retry.
One secret per listener
One secret per listener
Don’t reuse a secret across environments. A staging listener and a production listener have distinct secrets by design — treat them as separate credentials.
Related events
Webhooks (overview)
Why webhooks, delivery guarantees and the payload format.
user_received_badge
Full reference page for an event — payload, headers and example receiver.
