Source: https://docs.debitura.com/api/customer-api/test-cases

# Test cases — Customer API

Drive test cases through lifecycle states without manual intervention. POST /test/cases/{id}/advance activates or closes a test case in a single call, triggering the real webhook pipeline so your handlers can be verified end-to-end. Hard-delete by ID or tag to keep CI environments clean between runs.

Base URL: `https://customer-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/customer-api.json). Examples are schema illustrations, not observed responses. Complete schemas, including recursive types, are in OpenAPI.

<a id="advance-a-test-case-to-a-known-lifecycle-state"></a>

## Advance a test case to a known lifecycle state.

`POST /test/cases/{id}/advance`

Drives a test case to a well-known lifecycle state in a single call.

**Purpose:**
Enables CI pipelines and integrators to exercise the full collection lifecycle — including real webhooks and events — without manual intervention.

**Target States:**
- `Active` — Activates the case from PendingVerification or PendingVerificationInternal. No-op if already Active or Closed.
- `Closed:Paid` — Records a payment for `amount` and closes the case as Paid. Activates the case first if needed. `amount` is required.
- `Closed:NoPayment` — Closes the case with PreLegalExhaustedNoPayment. Activates the case first if needed.

**Guards:**
- Returns 400 if the case is not a test case (Classification != Test).
- Returns 400 if `amount` is missing when `to` is `Closed:Paid`.
- Returns 400 if `to` is not one of the valid values.
- Returns 400 if the case is already closed with a different close code (e.g. already Closed:NoPayment when requesting Closed:Paid).
- Returns 404 if the case is not found or not owned by the calling creditor.

**No-op behaviour:**
If the case is already at the requested state, the call returns 200 with `advanced: false` and the current state — no changes are made.

**Webhooks:**
Transitions use the real internal service pipeline. Webhook delivery per target:

- `→ Active`: fires `case.updated` to Creditor subscriptions.
- `→ Closed:Paid`: fires `payment.created` and `case.updated` and `case.closed` to Creditor subscriptions.
- `→ Closed:NoPayment`: fires `case.updated` and `case.closed` to Creditor subscriptions.

All events carry `classification: test` and are only delivered to webhook subscriptions registered with `classification: test`.

**How to Test:**

1. **Create a test case** — `POST /cases` with `isTest: true` and `tag: suite-run-{uuid}`. Note the returned `id`.

2. **Register a test webhook subscription** — subscribe to the events you want to assert on (`case.updated`, `payment.created`, `case.closed`) with `classification: test` and point the URL to your test receiver (e.g. a local ngrok tunnel or a CI webhook sink).

3. **Advance to Active** — `POST /test/cases/{id}/advance` with `{ "to": "Active" }`. Expect `{ advanced: true, state: "Active" }` and a `case.updated` event on your Creditor subscription.

4. **Advance to Closed:Paid** — `POST /test/cases/{id}/advance` with `{ "to": "Closed:Paid", "amount": 1000.00 }`. Expect `{ advanced: true, state: "Closed:Paid" }` and a `payment.created` event on your Creditor subscription.

5. **Verify final state** — `GET /cases/{id}` and assert `lifecycle: Closed` and `closeCode: Paid`.

6. **Test no-op** — Call the same advance again. Expect `{ advanced: false, state: "Closed:Paid" }` and no new webhook events.

7. **Test mismatch error** — With the case closed as Paid, call `{ "to": "Closed:NoPayment" }`. Expect 400 with a message describing the conflict.

8. **Assert webhooks** — `GET /webhooks/events?caseId={id}` to verify which events fired.

9. **Reset between runs** — `DELETE /test/cases?tag=suite-run-{uuid}` to clean up all cases created in this run.

### Path parameters

- `id` (uuid, required): 

### Request body (application/json)

- `to` (string, required, nullable): The target state to advance the case to.
Valid values: "Active", "Closed:Paid", "Closed:NoPayment"
- `amount` (number, nullable): Payment amount (required when To is "Closed:Paid").
Must be a positive value in the case currency.

```json
{
  "to": "Active",
  "amount": 1500
}
```

### Response 200

Advance result (advanced=true if state changed, advanced=false if already there)

- `advanced` (boolean): True if the case was advanced in this call; false if it was already at or past the target state (no-op).
- `state` (string, nullable): The current state of the case after this call.
One of: "Active", "Closed:Paid", "Closed:NoPayment", "Closed" (for other close codes).

```json
{
  "advanced": true,
  "state": "string"
}
```

### Response 400

Validation error — non-test case, missing amount, or unknown target state

### Response 404

Case not found or not owned by this creditor

### Response 500

Internal server error

<a id="hard-delete-a-single-test-case-by-id"></a>

## Hard-delete a single test case by ID.

`DELETE /test/cases/{id}`

Permanently removes a test case and all its child entities (payments, chats, files, timeline entries, webhook delivery records) from the database.

**This is a hard-delete.** The row is removed entirely — there is no soft-delete or recovery path. This is intentional for CI environments that create many test cases per day.

**Guards:**
- Returns 400 if the case is classified as Production. Only Test cases may be deleted via this endpoint.
- Returns 404 if the case is not found or not owned by the calling creditor.

**Idempotent:** Returns 204 even if the case is already deleted (no-op).

### Path parameters

- `id` (uuid, required): 

### Response 204

Case deleted (or already absent — idempotent)

### Response 400

Case is a Production case — deletion rejected

### Response 404

Case not found or not owned by this creditor

### Response 500

Internal server error

<a id="hard-delete-all-test-cases-with-the-given-tag"></a>

## Hard-delete all test cases with the given tag.

`DELETE /test/cases`

Permanently removes all test cases created with the specified tag (and all their child entities) from the database.

**Scoped cleanup:** Each CI pipeline run should create cases with a unique tag (e.g. `suite-run-{uuid}`) and use this endpoint at the end of the run to clean up, without affecting cases from parallel pipeline runs.

**This is a hard-delete.** Rows are removed entirely with no recovery path. This is intentional for CI environments.

**Guards:**
- Returns 400 if any matched case is classified as Production. The entire operation is rejected and nothing is deleted.
- Returns 400 if the tag query parameter is missing or blank.

**Idempotent:** Returns 204 even if no cases match the tag — no error is raised.

### Query parameters

- `tag` (string): 

### Response 204

Cases deleted (or none matched — idempotent, no response body)

### Response 400

Tag is missing/blank, or matched cases include a Production case

### Response 500

Internal server error
