Source: https://docs.debitura.com/api/collection-partner-api/test-webhooks

# Test webhooks — Collection Partner API

Fire synthetic webhook events against test cases without driving the case to the state that would naturally produce them. POST /test/webhooks/fire emits any event type (case.assigned, case.updated, case.closed, payment.created, payment.deleted, chat.created) against a test case — useful for testing rare or hard-to-reach event handlers in isolation.

Base URL: `https://collectionpartner-api.debitura.com`

Authentication: `XApiKey` API key; see [authentication](https://docs.debitura.com/developer-concepts/authentication.md).

Generated from [OpenAPI](https://docs.debitura.com/openapi/collection-partner-api.json). Examples are schema illustrations, not observed responses. Complete schemas, including recursive types, are in OpenAPI.

<a id="fire-a-named-webhook-event-type-for-a-test-case"></a>

## Fire a named webhook event type for a test case.

`POST /test/webhooks/fire`

Fires a real current-state webhook event for any registered Collection Partner event type against a test case — even if the case hasn't naturally reached the state that would produce that event.

**Purpose:**
Unblocks testing webhook handlers for rare or hard-to-reach event types (e.g. `case.closed`, `chat.created`) without having to drive the case through its full lifecycle.

**Payload:**
The event carries the real current state of the case — fields are read from the case as it exists now. No payload fabrication or override is supported in this version.

**Event types:**
- `case.assigned` — current lifecycle
- `case.declined` — current case identity, without a fabricated decline reason
- `case.updated` — current lifecycle (oldLifecycle and newLifecycle both reflect current state)
- `case.closed` — current close code and comment (use after case is already closed, or to test your handler regardless)
- `payment.created` — most recent payment on the case (returns 422 if no payments exist)
- `payment.deleted` — most recently deleted payment on the case (returns 422 if no payments have been deleted)
- `chat.created` — most recent chat message on the case (returns 422 if no chats exist)

**Managing-role events (feature must be enabled):**
`managed_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.created`.
Requires a currently owned managing Test case and a Test subscription selecting the exact event.
Chat uses the current active engagement only; missing payment/chat/collector fixtures return 422.
Notifications omit chat body and close/decline comments.

**Target subscriptions:**
- If `subscriptionId` is provided, fires only to that subscription. Returns 400 if the subscription is not found, not a test subscription, or not owned by this partner.
- If omitted, fires to all active test subscriptions registered for the given event type.

**Event log (asynchronous):**
The synthetic fire is enqueued into the normal delivery pipeline, exactly like a real dispatch. A successful response (and its `enqueuedCount`) confirms the event was queued — it does **not** mean a row already exists in the webhook event log. The `WebhookEvent` row appears in `GET /webhooks/events` only after the worker drains the queue and attempts delivery — usually within a few seconds, but allow up to ~30 seconds, as the queue drain can lag under load. Do not assume the row is present the instant this call returns: poll `GET /webhooks/events?caseId={id}` with a short backoff until the event appears (or a ~30s timeout elapses) rather than reading it once immediately.

**Guards:**
- Returns 400 if the case is not a test case (`classification != test`), the event type is not valid, or the subscription is not found/not owned.
- Returns 404 if the case is not found or not owned by this collection partner.
- Returns 404 for `chat.created` while the case awaits Debitura approval or contract signing.
- Returns 422 if required data is missing (e.g. no payments for `payment.created`, no chats for `chat.created`).

### Request body (application/json)

- `event` (string, required, nullable): The webhook event type to fire (e.g. "case.updated", "payment.created").
Must be a valid event type for the calling API — refer to each API's documentation
for the supported list (Collection Partner and Customer API accept different sets).
- `caseId` (uuid, required): The ID of the test case to use as the event source.
- `subscriptionId` (uuid, nullable): Optional — the specific subscription ID to fire to.
If omitted, fires to all active test subscriptions for the calling API subscriber
that are registered for the given event type.

```json
{
  "event": "case.updated",
  "caseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "subscriptionId": "6b7a1f23-9c48-4e72-a901-1d2b3e4f5a6b"
}
```

### Response 200

Event fired — delivery jobs enqueued

- `eventType` (string, nullable): The event type that was fired (e.g. "case.updated").
- `caseId` (uuid): The case ID the event was fired for.
- `enqueuedCount` (integer): Number of webhook delivery jobs enqueued.
Zero means no active test subscriptions were found for this event type.

```json
{
  "eventType": "string",
  "caseId": "3f2b6c1e-8a4d-4b7f-9c2e-5d1a0b9e7f31",
  "enqueuedCount": 42
}
```

### Response 400

Validation error — non-test case, invalid event type, or subscription not found

- `error` (string, nullable): Short human-readable error label (legacy field — preserved for backward compatibility).
- `message` (string, nullable): Human-readable error description (legacy field — preserved for backward compatibility).
- `businessErrors` (array of objects, nullable): Canonical structured error array. Consumers should migrate to reading this field.
- `businessErrors[].type` (string, nullable): The type of business error (e.g., "MissingDebtCollectionContract", "MissingPowerOfAttorney", "NoPartnerAvailable").
- `businessErrors[].message` (string, nullable): A human-readable description of the error.
- `businessErrors[].solutionUrl` (string, nullable): A URL where the user can resolve this <i>specific</i> error (e.g., sign a contract).
            

Partners who want a <b>single URL</b> that walks the user through every pending
signing in one chain — instead of forwarding one URL per
`BusinessErrorApiDTO` — should use
SigningHandoff's `CombinedSigningUrl`.
The two are complementary: `SolutionUrl` is granular per-error;
`CombinedSigningUrl` is the chain-walking alternative for signing-related errors.

```json
{
  "error": null,
  "message": "Payment plan agreed with the debtor.",
  "businessErrors": [
    {
      "type": "string",
      "message": "Payment plan agreed with the debtor.",
      "solutionUrl": "https://app.debitura.com/…"
    }
  ]
}
```

### Response 404

Case not found or not owned by this collection partner

- `error` (string, nullable): Short human-readable error label (legacy field — preserved for backward compatibility).
- `message` (string, nullable): Human-readable error description (legacy field — preserved for backward compatibility).
- `businessErrors` (array of objects, nullable): Canonical structured error array. Consumers should migrate to reading this field.
- `businessErrors[].type` (string, nullable): The type of business error (e.g., "MissingDebtCollectionContract", "MissingPowerOfAttorney", "NoPartnerAvailable").
- `businessErrors[].message` (string, nullable): A human-readable description of the error.
- `businessErrors[].solutionUrl` (string, nullable): A URL where the user can resolve this <i>specific</i> error (e.g., sign a contract).
            

Partners who want a <b>single URL</b> that walks the user through every pending
signing in one chain — instead of forwarding one URL per
`BusinessErrorApiDTO` — should use
SigningHandoff's `CombinedSigningUrl`.
The two are complementary: `SolutionUrl` is granular per-error;
`CombinedSigningUrl` is the chain-walking alternative for signing-related errors.

```json
{
  "error": null,
  "message": "Payment plan agreed with the debtor.",
  "businessErrors": [
    {
      "type": "string",
      "message": "Payment plan agreed with the debtor.",
      "solutionUrl": "https://app.debitura.com/…"
    }
  ]
}
```

### Response 422

Required data missing (e.g. no payments for payment.created)

- `error` (string, nullable): Short human-readable error label (legacy field — preserved for backward compatibility).
- `message` (string, nullable): Human-readable error description (legacy field — preserved for backward compatibility).
- `businessErrors` (array of objects, nullable): Canonical structured error array. Consumers should migrate to reading this field.
- `businessErrors[].type` (string, nullable): The type of business error (e.g., "MissingDebtCollectionContract", "MissingPowerOfAttorney", "NoPartnerAvailable").
- `businessErrors[].message` (string, nullable): A human-readable description of the error.
- `businessErrors[].solutionUrl` (string, nullable): A URL where the user can resolve this <i>specific</i> error (e.g., sign a contract).
            

Partners who want a <b>single URL</b> that walks the user through every pending
signing in one chain — instead of forwarding one URL per
`BusinessErrorApiDTO` — should use
SigningHandoff's `CombinedSigningUrl`.
The two are complementary: `SolutionUrl` is granular per-error;
`CombinedSigningUrl` is the chain-walking alternative for signing-related errors.

```json
{
  "error": null,
  "message": "Payment plan agreed with the debtor.",
  "businessErrors": [
    {
      "type": "string",
      "message": "Payment plan agreed with the debtor.",
      "solutionUrl": "https://app.debitura.com/…"
    }
  ]
}
```

### Response 500

Internal server error

- `error` (string, nullable): Short human-readable error label (legacy field — preserved for backward compatibility).
- `message` (string, nullable): Human-readable error description (legacy field — preserved for backward compatibility).
- `businessErrors` (array of objects, nullable): Canonical structured error array. Consumers should migrate to reading this field.
- `businessErrors[].type` (string, nullable): The type of business error (e.g., "MissingDebtCollectionContract", "MissingPowerOfAttorney", "NoPartnerAvailable").
- `businessErrors[].message` (string, nullable): A human-readable description of the error.
- `businessErrors[].solutionUrl` (string, nullable): A URL where the user can resolve this <i>specific</i> error (e.g., sign a contract).
            

Partners who want a <b>single URL</b> that walks the user through every pending
signing in one chain — instead of forwarding one URL per
`BusinessErrorApiDTO` — should use
SigningHandoff's `CombinedSigningUrl`.
The two are complementary: `SolutionUrl` is granular per-error;
`CombinedSigningUrl` is the chain-walking alternative for signing-related errors.

```json
{
  "error": null,
  "message": "Payment plan agreed with the debtor.",
  "businessErrors": [
    {
      "type": "string",
      "message": "Payment plan agreed with the debtor.",
      "solutionUrl": "https://app.debitura.com/…"
    }
  ]
}
```
