Start with the delivery log
Almost every webhook problem is answered by the delivery log. It shows, per delivery, thestatus, the number of attempts, the HTTP code of the last attempt (lastStatusCode) and the text of the last failure (lastError) — but never the payload.
I am not receiving any events
isActive: true means you have not disabled the subscription and the circuit breaker has not tripped. It does not prove deliveries are reaching your endpoint: while isEchoActive is true they are diverted to the capture endpoint instead of your URL, and an archived case emits nothing at all.Deliveries show FAILED or EXHAUSTED
FAILED means the last attempt did not succeed and a retry is scheduled (nextRetryAt is set). EXHAUSTED means the delivery is final — either all 5 attempts failed, or it was cancelled because the subscription was disabled or deleted before it could be sent. Retries follow the ladder 30 s, 2 min, 10 min, 30 min — about 43 minutes end to end.
Your endpoint must answer 2xx for an attempt to count as delivered. 3xx, 4xx, 5xx, a timeout and a TLS or connection failure are all failed attempts. Return 2xx as soon as the body is durably stored and do the real work asynchronously.
Reliability lists every lastError string and what each one means. These three are the ones that get misread:
Signature does not verify
The header isX-CaseXchange-Signature: t=<unix-seconds>,v1=<hex>. v1 is the hex HMAC-SHA256, keyed with your secret, over the string <t>.<rawBody> — the integer t from the header, a dot, and the exact request body bytes. See Verifying signatures for reference code.
For 24 hours after a rotation, echo captures also accept the previous secret for the
signatureValid read-back check only. Outbound deliveries to your endpoint are always signed with the current secret alone, so a capture that says signatureValid: true right after a rotation does not mean your old secret still works.Management calls fail
Every error uses the standard envelope — branch onerror.code and keep meta.requestId for support. Managing subscriptions carries the full error table for these eleven endpoints, with the exact trigger for every code, and Error Handling covers the general pattern. Read those first; the rows below are only the ones where the code you get points somewhere other than the problem.
I get duplicates, events out of order, or my own changes
My subscription turned itself off
After 10 consecutive exhausted deliveries — that is, 10 deliveries in a row that each failed all 5 attempts — the circuit breaker deactivates the subscription. It stays listed withisActive: false. A successful delivery at any point resets the count.
While the subscription is inactive, no deliveries are created for it. Events that occur during that time are not delivered later — there is no backfill — so reconcile from the API once you are back.
1
Find the failure pattern
Read
GET /webhooks/{id}/deliveries and look at lastError and lastStatusCode on the EXHAUSTED records. Reliability maps every lastError value to its cause, and Deliveries show FAILED or EXHAUSTED covers the three that are easiest to misread.2
Fix the endpoint
Ten exhausted deliveries in a row means the endpoint kept failing across full retry ladders of about 43 minutes each, not a single blip. Confirm it is publicly reachable on port 443, returns
2xx within the timeouts, does not redirect, and resolves to public addresses.3
Re-enable the subscription
400 subscription_limit_reached means another subscription must be deactivated or deleted first.Reactivating also clears the consecutive-exhausted count, so the subscription starts clean: it takes another 10 exhausted deliveries in a row to trip the breaker again.4
Confirm with a test delivery
GET /webhooks/{id}/deliveries until the webhook.test record reads DELIVERED.5
Reconcile
Re-read the cases that changed while the subscription was off from
GET /status-updates, GET /sent-cases and GET /received-referrals.Deleting the subscription instead of re-enabling it also works, but a new subscription gets a new id and a new secret, and it too starts with no backfill.
Contacting support
Emailhelp@casexchange.com. Include the following so the team can trace the delivery end to end:
Never send your API key, your signing secret or your echo token. Support does not need them and cannot read the secret back either — if you believe one is compromised, rotate it with
POST /webhooks/{id}/rotate-secret or generate a new key.
Reliability
Retry ladder, delivery statuses, circuit breaker and retention.
Testing webhooks
Test deliveries and echo mode for debugging without a public endpoint.
Verifying signatures
Reference verifiers and secret rotation.
Known gaps
Changes that produce no event, and how to detect them.

