Webhook & Test-Mode Strategy
This page is the single source of truth for the webhook and test-mode design across Debitura's public APIs. It covers how test and live subscriptions work, the CI loop primitives available on each API, and where each auxiliary capability fits.
Core design principle
Core CI-loop primitives are symmetric across the Customer API and Collection Partner API. Auxiliary primitives exist where they are genuinely needed, not for symmetry's sake.
Test vs live subscriptions
See Test vs Live Subscriptions for how isTestMode works, immutability, and running test and live subscriptions simultaneously.
The 4-step CI loop
The complete test loop follows four steps:
CREATE → DRIVE → ASSERT → RESET
- CREATE — create a test case with
isTest: trueand a run-scopedtag - DRIVE — call
advanceto move the case to a target lifecycle state - ASSERT — call
GET /webhooks/events?caseId={id}to verify what fired and was delivered - RESET — call
DELETE /test/cases?tag={tag}to hard-delete all run data
See CI Testing for the full implementation with code examples.
Per-API capability matrix
Core CI loop — symmetric (Customer API + Collection Partner API)
| Primitive | Customer API | Collection Partner API | Notes |
|---|---|---|---|
| Create test case | POST /cases with isTest: true | POST /managed-cases with isTest: true | Tag the case for scoped cleanup |
| Advance lifecycle | POST /test/cases/{id}/advance | POST /test/cases/{id}/advance | Same request body |
| Hard-delete by tag | DELETE /test/cases?tag= | DELETE /test/cases?tag= | |
| Hard-delete by ID | DELETE /test/cases/{id} | DELETE /test/cases/{id} | |
| Delivery history | GET /webhooks/events | GET /webhooks/events | Filter by caseId and since |
| Replay by event ID | POST /webhooks/events/{id}/replay | POST /webhooks/events/{id}/replay | Re-enqueues the exact original payload |
fire — symmetric (Customer API + Collection Partner API)
POST /test/webhooks/fire fires a named event type for a test case without advancing the lifecycle. Use it to test your handler in isolation — emit case.closed without actually closing the case.
Valid event types differ by API because the event vocabularies differ:
| API | Valid event types |
|---|---|
| Customer API | case.created, case.updated, case.closed, payment.created, chat.created |
| Collection Partner API | case.assigned, case.updated, case.closed, payment.created, chat.created |
payment.created returns 422 if no payments exist on the case. chat.created returns 422 if no chats exist.
replay-last-event — Collection Partner API only (by design)
POST /test/cases/{id}/replay-last-event replays the most recent webhook event for a case without needing to look up the event ID.
This endpoint is Collection Partner-only and is intentionally not ported to the Customer API. It was added as a stopgap when the Collection Partner API lacked a delivery history endpoint. Now that GET /webhooks/events is available on both APIs, replay-last-event is redundant — but it is kept for backward compatibility and documented here as a thin convenience wrapper over GET /webhooks/events + POST /webhooks/events/{id}/replay.
Use replay-by-id in new integrations. Use replay-last-event only when you genuinely don't want to enumerate event history.
Referral Partner API — separate model
The Referral Partner API uses a separate isolated test-environment model. There are no in-row test cases or isTestMode subscriptions. Instead, test events are fired via POST /v1/webhooks/test against the dedicated Referral Partner test environment at testreferral-api.debitura.com.
The Customer API and Collection Partner API CI-loop primitives described above do not apply to the Referral Partner API.
Other webhook capabilities
Signature verification
Every delivery includes an X-Debitura-Signature header for HMAC-SHA256 verification. See Signature Verification for implementation details and code examples.
Retry and auto-disable
Failed deliveries use up to 8 total delivery attempts with exponential backoff. A subscription is automatically disabled after all 8 attempts fail, or if your endpoint returns 410 Gone. See Retry Behavior for the full schedule.
Idempotency
The event id field in every payload is a stable UUID. Track it to deduplicate replayed or retried deliveries. Replayed events also include the header X-Debitura-Replay: true. See Idempotency: webhook consumption.
Local development
Use a tunneling tool (ngrok, cloudflared) to expose a local port and point a test subscription at it. See Local Development.