Skip to main content

Webhooks

Receive real-time notifications when case events occur instead of polling the API.

This guide assumes you've completed the Quickstart.

Overview

Webhooks push event data to your endpoint as cases progress through collection. Subscribe to specific events to keep your systems synchronized without repeated API calls.

Available Events

EventDescription
case.createdNew case submitted
case.updatedCase lifecycle state changed
case.closedCase resolved (paid, written off, or otherwise closed)
payment.createdPayment registered on a case
payment.deletedPayment deleted (reversed) on a case
chat.createdChat message added to a case

Create a Webhook Subscription

You can create webhooks via the API (shown below) or through the Debitura portal. See Webhooks in the portal for UI instructions.

Create webhook request
POST https://customer-api.debitura.com/webhooks
Content-Type: application/json
XApiKey: YOUR_API_KEY

{
"url": "https://your-domain.com/webhooks/debitura",
"events": ["case.created", "case.updated", "case.closed", "payment.created"],
"isTestMode": false
}

Request body parameters:

ParameterTypeDefaultDescription
urlstringThe 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 changed later via PATCH /webhooks/{id} with isTestMode.
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.

201Created
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "https://your-domain.com/webhooks/debitura",
"events": ["case.created", "case.updated", "case.closed", "payment.created"],
"isActive": true,
"isTestMode": false,
"createdUtc": "2026-01-31T15:23:45Z",
"updatedUtc": "2026-01-31T15:23:45Z",
"disabledReason": null,
"secret": "dGhpc2lzYWJhc2U2NGVuY29kZWRzZWNyZXQ="
}
Save Your Secret

The secret is returned only once during creation. Store it immediately. You cannot retrieve it later.

To regenerate: PATCH /webhooks/{id} with "regenerateSecret": true.

Event Payload Structure

All events use a CloudEvents-inspired format:

Event envelope structure
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"specVersion": "1.0",
"event": "case.created",
"timestamp": "2026-01-31T15:23:45Z",
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W"
},
"links": {
"self": "https://customer-api.debitura.com/cases/123e4567-e89b-12d3-a456-426614174000"
}
}
FieldDescription
idUnique event ID—use for idempotency
eventEvent type
timestampWhen the event occurred (ISO 8601 UTC)
dataEvent-specific payload
links.selfAPI URL for the affected resource

HTTP Headers:

HeaderValue
X-Debitura-Signaturet={timestamp},v1={signature}
X-Debitura-TimestampUnix timestamp

The event type is available in the JSON body under the event field.

Event Payloads

case.created

{
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W",
"lifecycle": "Pending contract signing"
}
}
FieldDescription
caseIdDebitura's internal case ID
referenceDebitura case reference (e.g. Q8OAXF3W)
lifecycleInitial lifecycle state — useful when you need to know whether contracts are still pending without a separate API call. See Case Lifecycle for all possible values.

case.updated

{
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W",
"oldLifecycle": "Active",
"newLifecycle": "Pending Verification"
}
}

See Case Lifecycle for all lifecycle values and their meanings.

case.closed

{
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W",
"closeCode": "Paid",
"closeComment": "Paid in full by debtor"
}
}

See Case Lifecycle for all close codes and their meanings.

payment.created

{
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W",
"paymentId": "789e4567-e89b-12d3-a456-426614174999",
"amount": 5000.00,
"currency": "EUR",
"date": "2026-01-31T12:00:00Z"
}
}

payment.deleted

Fires when a payment is deleted (reversed) on your case — for example a client correcting a payment that was recorded with the wrong amount. Same payload shape as payment.created; date still reflects the original payment date, not when it was deleted (use the event's top-level timestamp for that).

{
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W",
"paymentId": "789e4567-e89b-12d3-a456-426614174999",
"amount": 5000.00,
"currency": "EUR",
"date": "2026-01-31T12:00:00Z"
}
}

chat.created

{
"data": {
"caseId": "123e4567-e89b-12d3-a456-426614174000",
"reference": "Q8OAXF3W",
"chatId": "456e4567-e89b-12d3-a456-426614174888",
"role": "Partner",
"message": "Please provide updated payment plan"
}
}

Role values: Partner (collection partner), Creditor (you), ManagedByPartner (partner acting on your behalf)

Signature Verification

Verify every webhook request using webhook signature verification. The signature proves the request came from Debitura and wasn't tampered with.

Quick summary:

  1. Extract t (timestamp) and v1 (signature) from X-Debitura-Signature
  2. Construct: signed_payload = timestamp + "." + raw_json_body
  3. Decode your secret from Base64
  4. Compute HMAC-SHA256 of signed payload
  5. Compare signatures using constant-time comparison
  6. Verify timestamp is within 5 minutes

Processing Best Practices

Respond Quickly

Return 2xx within 10 seconds. Verify the signature, acknowledge immediately, then process the event asynchronously via a queue or background job.

Idempotent Processing

Use the id field to detect duplicates—Debitura may retry delivery. Store processed event IDs and skip duplicates. See idempotent webhook processing for implementation patterns.

Retry Behavior

Debitura retries failed deliveries with exponential backoff:

AttemptDelayCumulative
10s0s
2~60s~1 min
3~120s~3 min
4~240s~7 min
5~480s~15 min
6~960s~31 min
7~1800s~1 hour
8~1800s~1.5 hours

After 8 consecutive failures (1 initial delivery + 7 retries), the webhook is automatically disabled. Fix your endpoint and re-enable via the API.

A 410 Gone response immediately disables the webhook with reason "Endpoint returned 410 Gone (endpoint retired)".

Managing Webhooks

List subscriptions:

List all webhooks
GET https://customer-api.debitura.com/webhooks

Update subscription:

Update webhook
PATCH https://customer-api.debitura.com/webhooks/{id}

{
"url": "https://new-endpoint.com/webhooks",
"isActive": true
}

The PATCH body accepts url, isActive, isTestMode, and regenerateSecret. Event subscriptions are immutable — sending events in a PATCH returns 400 (WebhookEventsImmutable). To change which events a subscription receives, delete it and create a new one.

Delete subscription:

Delete webhook
DELETE https://customer-api.debitura.com/webhooks/{id}

Test delivery:

Test webhook delivery
POST https://customer-api.debitura.com/webhooks/{id}/test

Test deliveries include X-Debitura-Test: true header.

Action routes use a slash

Webhook action endpoints use a slash sub-route (/test, /replay). An older colon form ({id}:test) still works, but only if you percent-encode the colon as %3A ({id}%3Atest) — a literal : returns 404. Use the slash form; it is canonical.

Delivery History & Replay

To inspect what's been delivered to a subscription, or to re-deliver a specific event, use the webhook events endpoints:

List delivered events for a case:

List webhook events for a case
GET https://customer-api.debitura.com/webhooks/events?caseId={caseId}
XApiKey: YOUR_API_KEY

Replay a specific event:

Replay a specific event
POST https://customer-api.debitura.com/webhooks/events/{eventId}/replay
XApiKey: YOUR_API_KEY

This re-enqueues that exact payload for redelivery to the subscription's current endpoint. The endpoint targets this specific subscription only — it does not affect other subscriptions on your account.

Auto-generated API reference: List webhook events dispatched for a case, Replay a specific webhook event.

Deprecated: POST /webhooks/{id}/replay

An older, differently-shaped endpoint at this same path only counts case.created events since a timestamp — it does not redeliver anything, despite the name. It's kept for backward compatibility but shouldn't be used going forward; use the two endpoints above instead. See the WebhookEvents reference for details.

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. The Customer API is the primary example used throughout that guide. See CI Testing for the full walkthrough and code examples.

Troubleshooting

Webhook not received

Your endpoint must be publicly accessible via HTTPS with a valid TLS certificate. Private IP addresses and localhost are blocked.

Signature verification fails

Ensure you're using the raw request body (not parsed JSON) and decoding the secret from Base64 before computing HMAC.

Webhook disabled

Check disabledReason in the webhook details. Fix the underlying issue, then update with "isActive": true.

For a fuller error-message reference, see Webhook Troubleshooting.