Webhooks
Subscribe to real-time event notifications for cases assigned to your agency, lifecycle changes, payments, and chat messages.
Create a Webhook Subscription
POST https://collectionpartner-api.debitura.com/webhooks
Content-Type: application/json
XApiKey: your_api_key_here
{
"Url": "https://your-platform.com/webhooks/debitura",
"Events": [
"case.assigned",
"case.updated",
"case.closed",
"case.declined",
"payment.created",
"payment.deleted",
"chat.created"
],
"IsTestMode": false
}
Request body parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
Url | string | — | The HTTPS endpoint to deliver events to |
Events | string[] | — | Event types to subscribe to (see Available Events) |
IsTestMode | boolean | false | When true, this subscription only receives webhook events from test cases. When false (default), it receives events from live production cases. Can be toggled later via PUT /webhooks/{id}, which re-classifies the subscription between test and live in place. |
During integration development, set "IsTestMode": true to receive events from test cases only — your live production data is unaffected. See Test vs Live subscriptions for details.
Response (201 Created):
{
"Id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"Url": "https://your-platform.com/webhooks/debitura",
"Events": [
"case.assigned",
"case.updated",
"case.closed",
"case.declined",
"payment.created",
"payment.deleted",
"chat.created"
],
"IsActive": true,
"IsTestMode": false,
"CreatedUtc": "2026-05-29T09:15:00Z",
"UpdatedUtc": "2026-05-29T09:15:00Z",
"DisabledReason": null,
"Secret": "dGhpc2lzYWJhc2U2NGVuY29kZWRzZWNyZXQ="
}
The Secret is only returned once during creation. Store it immediately in your secrets manager. You cannot retrieve it later. If lost, regenerate via PUT /webhooks/{id} with RegenerateSecret: true.
Manage Subscriptions
GET https://collectionpartner-api.debitura.com/webhooks
XApiKey: your_api_key_here
GET https://collectionpartner-api.debitura.com/webhooks/{id}
XApiKey: your_api_key_here
PUT https://collectionpartner-api.debitura.com/webhooks/{id}
Content-Type: application/json
XApiKey: your_api_key_here
{
"Url": "https://new-endpoint.com/webhooks",
"Events": ["case.assigned", "case.updated", "case.closed"],
"IsActive": true,
"RegenerateSecret": false
}
DELETE https://collectionpartner-api.debitura.com/webhooks/{id}
XApiKey: your_api_key_here
For the full API reference, see Webhook endpoints.
Payload Structure
All events use a CloudEvents-inspired envelope format:
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique event ID — use for idempotency |
specVersion | string | Always "1.0" |
event | string | Event type (e.g., "case.assigned") |
timestamp | string (ISO 8601) | UTC time when the event occurred |
data | object | Event-specific payload (see sections below) |
links | object | Reserved — empty for collection partner events |
HTTP Headers on every delivery:
| Header | Value |
|---|---|
X-Debitura-Signature | t={timestamp},v1={signature} |
X-Debitura-Timestamp | Unix timestamp (seconds) |
For signature verification implementation, see Signature Verification.
Available Events
case.assigned
Fires when a case has been validated by Debitura and assigned to your agency. This is the starting event for a case — it confirms the case is yours to work. It is semantically distinct from case.created (which fires for creditor integrations at submission time): collection partners see case.assigned after Debitura's routing and validation step, not at submission.
{
"id": "7f3c9e1a-bb42-4d87-a123-556677889900",
"specVersion": "1.0",
"event": "case.assigned",
"timestamp": "2026-05-29T09:15:30Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"lifecycle": "Active"
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID. Use this to look up or reference the case via the Cases API. |
reference | string | Human-readable case reference (e.g., "Q8OAXF3W"). Displayed in the Debitura portal and useful for support conversations. |
lifecycle | string | Lifecycle state at the moment of assignment (typically "Active"). See Case Lifecycle for all states. |
case.declined
Fires when you decline an exclusively-assigned case and it is sent back into the partner network. This is a distinct signal from case.updated — it exists specifically so your integration can remove the case from its own queue the moment you decline it, rather than inferring removal from a generic lifecycle change. Declining a case terminates your active engagement, ends any active collection period, and re-qualifies the case as an open lead for the rest of the partner network (excluding you).
{
"id": "c6d8e0f2-4a91-4b3d-a567-889900112233",
"specVersion": "1.0",
"event": "case.declined",
"timestamp": "2026-07-01T09:20:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"reason": "Outside our jurisdiction of operation"
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID |
reference | string | Human-readable case reference |
reason | string | null | The decline reason you provided when declining the case, if any |
case.updated
Fires when a case moves to a new lifecycle state — for example from Active to Paused, or when a progress update triggers a transition.
{
"id": "b2e4f8a0-dc61-4f92-b345-778899001122",
"specVersion": "1.0",
"event": "case.updated",
"timestamp": "2026-05-29T11:42:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"oldLifecycle": "Active",
"newLifecycle": "Paused"
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID |
reference | string | Human-readable case reference |
oldLifecycle | string | Lifecycle state before this transition |
newLifecycle | string | Lifecycle state after this transition |
See Case Lifecycle for all lifecycle states and valid transitions.
case.closed
Fires when a case reaches its terminal state. This is the final event for a case — no further case.updated events follow. Use it to update your internal records with the outcome and close code.
{
"id": "9c5a3d7b-ef84-4201-c678-990011223344",
"specVersion": "1.0",
"event": "case.closed",
"timestamp": "2026-05-29T14:05:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"closeCode": "Paid",
"closeComment": "Paid in full by debtor via bank transfer"
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID |
reference | string | Human-readable case reference |
closeCode | string | Reason the case was closed (e.g., "Paid", "Partially paid", "Debtor Insolvent/Bankrupt", "Case never started") |
closeComment | string | null | Optional additional context about the closure decision |
See Case Lifecycle for all close codes and their meanings.
payment.created
Fires when a payment is registered on a case assigned to your agency. This includes both payments you record yourself via the API and payments registered by other parties.
{
"id": "d1f6b2c8-a037-4512-d789-001122334455",
"specVersion": "1.0",
"event": "payment.created",
"timestamp": "2026-05-29T10:30:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"paymentId": "f4a7e9c2-b158-4823-e890-112233445566",
"amount": 12500.00,
"currency": "DKK",
"date": "2026-05-29T00:00:00Z"
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID |
reference | string | Human-readable case reference |
paymentId | string (UUID) | Unique identifier for this payment record |
amount | number (decimal) | Gross payment amount in the case currency |
currency | string | ISO 4217 currency code (e.g., "DKK", "EUR", "GBP") |
date | string (ISO 8601) | Date the payment occurred |
payment.deleted
Fires when a payment is deleted (reversed) on a case assigned to your agency — for example when correcting a payment reported with the wrong amount. Same recipients as payment.created: both the creditor and your agency are notified, so a reversal is never silent on either side.
{
"id": "a3e5c9f1-7d24-4b6a-9012-334455667788",
"specVersion": "1.0",
"event": "payment.deleted",
"timestamp": "2026-06-30T16:45:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"paymentId": "f4a7e9c2-b158-4823-e890-112233445566",
"amount": 12500.00,
"currency": "DKK",
"date": "2026-05-29T00:00:00Z"
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID |
reference | string | Human-readable case reference |
paymentId | string (UUID) | Identifier of the deleted payment record (same paymentId from its original payment.created event) |
amount | number (decimal) | Gross amount of the deleted payment, in the case currency |
currency | string | ISO 4217 currency code (e.g., "DKK", "EUR", "GBP") |
date | string (ISO 8601) | Date the (now-deleted) payment originally occurred — not the deletion timestamp; use the event's top-level timestamp for when the deletion happened |
chat.created
Fires when a chat message is posted on a case assigned to your agency. Chat messages are the primary communication channel between your agency and the creditor. Use this event to surface new messages in your own interface without polling.
{
"id": "e8a2c4f9-b361-4734-f901-223344556677",
"specVersion": "1.0",
"event": "chat.created",
"timestamp": "2026-05-29T13:15:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"chatId": "c7b5d3a1-e249-4615-c012-334455667788",
"role": "Creditor",
"message": "Please confirm whether the debtor has responded to the first notice."
},
"links": {}
}
| Field | Type | Description |
|---|---|---|
caseId | string (UUID) | Debitura's internal case ID |
reference | string | Human-readable case reference |
chatId | string (UUID) | Unique identifier for this chat message |
role | string | Who sent the message — "Creditor" (the case owner), "Partner" (your agency), or "ManagedByPartner" (your agency acting on behalf of a creditor in a managed-case flow) |
message | string | The full text content of the message |
Signature Verification
Always verify the X-Debitura-Signature header before processing events. See Signature Verification for implementation details and code examples.
Retry and Auto-disable
If your endpoint does not return a 2xx status within 10 seconds, Debitura retries with exponential backoff:
| Attempt | Delay before retry |
|---|---|
| 1 | Initial delivery |
| 2 | ~60 seconds |
| 3 | ~120 seconds |
| 4 | ~240 seconds |
| 5 | ~480 seconds |
| 6 | ~960 seconds |
| 7 | ~1800 seconds |
| 8 | ~1800 seconds |
Each delay includes ±10% random jitter to prevent thundering-herd problems across subscriptions.
Auto-disable triggers:
- Your endpoint returns
410 Gone— subscription is immediately disabled (signals the endpoint has been retired) - All 8 delivery attempts fail — subscription is disabled with reason
"Exceeded maximum retry attempts (8 failures)"
Re-enable after auto-disable: fix your endpoint, then call PUT /webhooks/{id} with "IsActive": true.
Secret Rotation
Rotate your signing secret without deleting and recreating the subscription:
PUT https://collectionpartner-api.debitura.com/webhooks/{id}
Content-Type: application/json
XApiKey: your_api_key_here
{
"RegenerateSecret": true
}
The response includes the new secret in the Secret field. Update your verification code immediately — the old secret stops working as soon as the response is received.
Testing Webhooks in CI
For running automated webhook tests, Debitura provides a full CI loop: create a test case, advance it through lifecycle states, inspect delivery history, and clean up — without pointing at an external receiver. See CI Testing for the full guide and code examples.
Business context: See Collection Partners: Case status definitions and allowed actions for what each lifecycle state and close code means in your collection workflow.
Troubleshooting
For diagnosing failed deliveries, decoding error messages in the delivery log, and other common issues, see Webhook Troubleshooting.