claim.collection_stage_changed— the claim moved to a new collection stage;claim.status_changed— the case status changed (open,disputed,closed), a closure with its reason (paid,installment_plan,written_off,withdrawn,disputed).
type enum (the envelope shape stays stable): acknowledge an event whose type you do not know with a 2xx and ignore it.
Setup
Webhooks are configured by an incaseof.law administrator on your behalf:- The admin opens Settings → Partners → Webhooks and selects your organization.
- They paste your HTTPS endpoint URL and click Create webhook.
- incaseof.law generates a signing secret and displays it once. The admin forwards it to you over a secure channel.
- Store the secret in your config — you’ll use it to verify every incoming request (see Signature verification below).
The endpoint URL must use HTTPS. Plain HTTP is rejected at config time.
Request format
Every delivery is aPOST to your configured URL with a JSON body.
Headers
Envelope
Every event uses the same envelope. Thedata field is shaped by type.
Signature verification
Each request includes anX-IcoLaw-Signature header of the form:
secret is the value the admin shared with you at setup time.
Rules
- Reject any request where
|now - t| > 5 minutes(replay protection). - After a secret rotation only the new secret is valid — there is no overlap window (see Secret rotation).
- Use a constant-time comparison (
crypto.timingSafeEqual/hmac.compare_digest). - Verify against the raw request body bytes, not a re-serialised version — JSON key order matters for the HMAC.
Reference implementations
Secret rotation
Either party can request a secret rotation through the admin team. When rotated:- A new signing secret is generated and shown to the admin once; the admin forwards it to you.
- From that moment every delivery is signed with the new secret only. There is no overlap window in which the previous secret still verifies.
- Deliveries your handler rejects until you have deployed the new secret are retried on the retry schedule — the last attempt comes about 7 h 12 min after the first (30 s + 2 min + 10 min + 1 h + 6 h). Agree a time for the rotation with the admin and deploy the new secret within that time, and nothing is lost.
Response & retry policy
Return any 2xx status code within 10 seconds to acknowledge the event. Anything else — non-2xx, timeout, connection error — is treated as a failure and triggers the next retry. Deliveries are sent by a job that runs every 30 seconds, so each time below can be up to 30 seconds later.
After the 6th attempt fails, the delivery is marked failed and is visible to the incaseof.law team. It is not sent again — failed deliveries are not re-fired. Reconcile once a day through
GET /openapi/claims (compare collection_stage with your mirror), so a missed event cannot leave your data behind.
While your webhook is disabled
No events are queued for a disabled webhook: stage changes in that time are not delivered later, and deliveries still pending when it was disabled are marked failed. After it is re-enabled, reconcile through the API.Best practices
Deduplicate
The sameX-IcoLaw-Delivery UUID (and the same body id) will arrive multiple times if any attempt fails and is retried. Persist the IDs you’ve already processed and short-circuit duplicates — pick one of the two and use it consistently:
Reconcile out-of-order events
Webhooks are eventually consistent. A retried older event can arrive after a newer one. Always reconcile bydata.claim_id + data.changed_at rather than assuming arrival order:
Don’t trust the payload for sensitive fields
The webhook payload deliberately contains no debtor PII (no name, no email, no address, no claim amount). If your downstream logic needs those fields, callGET /openapi/claims/{id} with your API token after receiving the event. This keeps the webhook signal-only and avoids exposing debtor data on whichever network your receiver sits on.
Verify before you parse
Verify the signature before doing anything else with the body — including JSON parsing. Reject with401 Unauthorized on signature mismatch.
What’s NOT included
Next steps
- See the Collection Stage Events reference for the payload shape and example bodies.
- Test the integration end-to-end by asking your admin to use the “Send test event” button in the webhooks tab — it fires a synthetic event with a fixed
claim_id(00000000-…-000000000000) so you can easily filter test traffic in your handler.