Skip to main content

Webhooks

Subscribe to real-time event notifications for cases assigned to your agency, lifecycle changes, payments, and chat messages. If you also submit cases for your own clients as a managing partner, you can opt in to a separate, minimal set of managed_case.* events for those cases.

Your role on the caseEventsWhere
Collecting — the case is assigned to your agencycase.assigned, case.updated, case.closed, case.declined, payment.created, payment.deleted, chat.createdAvailable Events
Managing — you submitted the case for your clientmanaged_case.created, managed_case.assigned, managed_case.updated, managed_case.closed, managed_case.declined, managed_case.payment.created, managed_case.payment.deleted, managed_case.chat.createdManaging-role events

The two catalogs are independent. Existing event names, payloads and URLs are unchanged, and no subscription receives a managed_case.* event unless it lists that exact name in Events.

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:

ParameterTypeDefaultDescription
Urlstring—The HTTPS endpoint to deliver events to
Eventsstring[]—Event types to subscribe to (see Available Events)
IsTestModebooleanfalseWhen 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.
Test mode

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="
}
Save Your Secret

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​

List all webhooks
GET https://collectionpartner-api.debitura.com/webhooks
XApiKey: your_api_key_here
Get a specific webhook
GET https://collectionpartner-api.debitura.com/webhooks/{id}
XApiKey: your_api_key_here
Update a webhook
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 a webhook
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:

FieldTypeDescription
idstring (UUID)Unique event ID — use for idempotency
specVersionstringAlways "1.0"
eventstringEvent type (e.g., "case.assigned")
timestampstring (ISO 8601)UTC time when the event occurred
dataobjectEvent-specific payload (see sections below)
linksobjectReserved — empty for collection partner events

HTTP Headers on every delivery:

HeaderValue
X-Debitura-Signaturet={timestamp},v1={signature}
X-Debitura-TimestampUnix 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.

case.assigned payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID. Use this to look up or reference the case via the Cases API.
referencestringHuman-readable case reference (e.g., "Q8OAXF3W"). Displayed in the Debitura portal and useful for support conversations.
lifecyclestringLifecycle state at the moment of assignment (typically "Pending Verification" — call POST /cases/{id}/start to make the case 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).

case.declined payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
reasonstring | nullThe 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.

case.updated payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
oldLifecyclestringLifecycle state before this transition
newLifecyclestringLifecycle state after this transition

See Case Lifecycle for all lifecycle states and valid transitions.

case.closed​

Fires when a case reaches its terminal state. A closed case can be reopened (for example when a payment is edited or deleted); you then receive a case.updated with oldLifecycle: "Closed". Use it to update your internal records with the outcome and close code.

case.closed payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
closeCodestringReason the case was closed (e.g., "Paid", "Partially paid", "Debtor Insolvent/Bankrupt", "Case never started")
closeCommentstring | nullOptional 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.

payment.created payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
paymentIdstring (UUID)Unique identifier for this payment record
amountnumber (decimal)Gross payment amount in the case currency
currencystringISO 4217 currency code (e.g., "DKK", "EUR", "GBP")
datestring (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.

payment.deleted payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
paymentIdstring (UUID)Identifier of the deleted payment record (same paymentId from its original payment.created event)
amountnumber (decimal)Gross amount of the deleted payment, in the case currency
currencystringISO 4217 currency code (e.g., "DKK", "EUR", "GBP")
datestring (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.

For an earlier partner's conversation, reference is empty when its case facts are unavailable. Use caseId to identify the case.

chat.created payload
{
"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": {}
}
FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
chatIdstring (UUID)Unique identifier for this chat message
rolestringWho 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)
messagestringThe full text content of the message

Managing-role events​

If you submit cases with POST /managed-cases, you can subscribe to eight additional events about those cases. They are separate from the collecting events above: different names, a smaller payload, and a different audience.

Who receives them. Only the partner that currently manages the case. A case you manage and also collect yourself produces both kinds of event, each with its own id; treat them as two independent streams.

Opt-in. A managing event is delivered only to a subscription whose Events list contains its exact name. There are no wildcards, and existing subscriptions are never opted in automatically. You can add the names to a subscription at any time:

PUT https://collectionpartner-api.debitura.com/webhooks/{id}
Content-Type: application/json
XApiKey: your_api_key_here

{
"Events": ["managed_case.created", "managed_case.assigned", "managed_case.updated", "managed_case.closed", "managed_case.payment.created"]
}

No historical backfill. Selecting an event starts delivery of events from that moment. Nothing that already happened is sent. To read the current state of existing cases, use the authorized managed-case endpoints.

Test and live stay separate. A subscription with IsTestMode: true receives managing events for test cases only; a live subscription receives them for live cases only. Every payload carries classification (production, test or demo) so you can assert on it.

Minimal by design. A managing notification tells you that something happened and which case it is about. It never contains chat text, close or decline comments, debtor details or any other case content. Fetch details through the managed-case API, which applies your current access.

Payload​

The envelope is the same as for every other event (id, specVersion "1.0", event, timestamp, data, links empty). Every managing event has these data fields; the event-specific fields follow in the next table.

FieldTypeDescription
caseIdstring (UUID)Debitura's internal case ID
referencestringHuman-readable case reference
classificationstringproduction, test or demo
managed_case.updated payload
{
"id": "5d1c7a42-93be-8f10-a6c4-0e7b2d9f3a18",
"specVersion": "1.0",
"event": "managed_case.updated",
"timestamp": "2026-10-12T08:30:00Z",
"data": {
"caseId": "e3d7f2a1-c845-4b9d-8f6e-aabbccddeeff",
"reference": "Q8OAXF3W",
"classification": "production",
"oldLifecycle": "Active",
"newLifecycle": "Active"
},
"links": {}
}

Event catalog​

EventFires whenEvent-specific data fields
managed_case.createdThe case has been submittedlifecycle
managed_case.assignedA collection partner has been assigned to the caselifecycle
managed_case.updatedThe case lifecycle is updatedoldLifecycle, newLifecycle
managed_case.closedThe case is closedcloseCode
managed_case.declinedThe assigned collection partner declined the casecollectingPartnerId (UUID)
managed_case.payment.createdA payment is registeredpaymentId (UUID), amount (decimal), currency, date
managed_case.payment.deletedA payment is reversedpaymentId, amount, currency, date — the original payment, unchanged
managed_case.chat.createdA chat message is postedchatId (UUID), role, caseEngagementId (UUID)

Field meanings match the same-named fields of the collecting events. Two points differ:

  • payment.deleted repeats the original payment snapshot. The event name is what tells you it was reversed; date is still the payment date, not the deletion time.
  • chat.created carries identifiers only, no message. role is the sender's role as in chat.created.

Timing​

Managing events are derived from the same moments as the collecting events, so their timing is exactly as precise as those signals — and no more:

  • managed_case.created is sent when the case is submitted.
  • managed_case.assigned is sent when assignment is signalled. Depending on the case that is immediately at submission or after Debitura's validation, so it can arrive right after managed_case.created or later. Do not infer that validation has happened from it, or assume a fixed gap.
  • managed_case.updated can carry equal oldLifecycle and newLifecycle values. Treat it as "something about the lifecycle was updated", not as a guaranteed phase change. There is no dedicated signal for a phase change or for reassignment to a different collection partner; to see the current assignee, read the case.
  • managed_case.declined is sent when the assigned collection partner declines. It does not name a reason.
  • Delivery is asynchronous and at-least-once, and events can arrive out of order. Use timestamp and the case data, not arrival order.

Chat notifications​

managed_case.chat.created identifies the conversation's engagement, including a retained historical engagement. Ending an engagement alone does not stop notifications or clear earlier payloads. The conversation must still be accessible and the case must still be managed by you.

When a delivery is not sent​

Before every delivery attempt, including each retry and each replay, Debitura re-checks that you are still entitled to the notification. If any check fails, no request is sent to your endpoint, no failed attempt is counted against the subscription, and no history entry is created. Reasons include:

  • the subscription was deleted, deactivated or no longer lists the event name;
  • the subscription's test/live mode does not match the case;
  • the case is no longer managed by you, was deleted, or belongs to an account that has been erased;
  • for chat, the conversation or its engagement is no longer available.

An entitlement check cannot be cancelled once your endpoint has been called: a request that has already started is not recalled. If Debitura temporarily cannot verify entitlement, it retries on the normal retry schedule and sends nothing until the check passes.

Event history​

Managing events appear in GET /webhooks/events?caseId={id} with eventType set to the managed_case.* name, like any other event. The stored payload is returned only while you still have access. When you do not — the case moved, the subscription no longer selects the event, the chat conversation or its engagement is no longer available, an account was erased, or 28 days have passed — the entry is still listed, but its payload is empty. Entries of a subscription you deleted are no longer listed at all.

The id of a history entry identifies the delivery record and is what you pass to the replay call. It is not the envelope id inside payload.

Replay​

POST /webhooks/events/{id}/replay re-sends the stored payload unchanged:

  • The delivery carries X-Debitura-Replay: true, and the envelope id is the same as the original. Deduplicate on id, not on the header: a replay of an event you already processed must not be applied twice.
  • Replay is available for 28 days after the event, and only while the entitlement checks above still pass. Otherwise the call returns 410 Gone (WebhookEventExpired). The same checks run again when the replay is delivered.
  • You can only replay events of your own subscriptions; an unknown ID, or an event of a deleted subscription, returns 404.
  • A replay creates a new history entry of its own; its envelope id equals the original's.

Receiver idempotency​

The id of a managing event is derived from the source event, the event name and your partner account. A retry or replay of the same notification always carries the same id; a different notification never shares one. Store processed id values and ignore repeats. Also ignore data fields you do not recognise, so an approved addition does not break your parser.

Testing managing events​

Use POST /test/webhooks/fire with a managing event name against a test case you currently manage (created with isTest: true via POST /managed-cases) and a test-mode subscription that selects that exact event. The event is built from the case's current state, so it uses real fixtures:

EventFixture the case must have
managed_case.payment.createdat least one payment
managed_case.payment.deletedat least one deleted payment
managed_case.chat.createda chat message on the case's active engagement
managed_case.assigned, managed_case.declineda collection partner assigned or engaged
StatusCause
200enqueuedCount is the number of deliveries queued. Without subscriptionId the event goes to all your active test subscriptions that select it, and enqueuedCount is 0 when there are none
400Not a test case, invalid event name, or the subscriptionId is not one of your test subscriptions that selects this event
404Case not found, or not a case you manage
422A required fixture above is missing

See CI Testing for a complete subscribe → fire → history → replay example.

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:

AttemptDelay before retry
1Initial 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.

A response that redirects (3xx) is treated as a failed attempt: Debitura does not follow redirects, so register the final URL.

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.