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

# Webhooks — Referral Partner API

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

<a id="get-all-webhooks-for-the-authenticated-referral-partner"></a>

## Get all webhooks for the authenticated referral partner

`GET /v1/Webhooks`

Returns all webhook subscriptions with their configuration (URL, events, status). Note: Secrets are never included in GET responses.

### Response 200

List of webhook subscriptions

- `id` (uuid): Unique identifier for the webhook subscription.
- `url` (string, nullable): The HTTPS URL where webhook events will be delivered.
- `events` (array of strings, nullable): Array of event types this subscription is interested in.
- `isActive` (boolean): Whether this webhook subscription is active.
- `createdUtc` (datetime): Timestamp when the webhook subscription was created (UTC).
- `updatedUtc` (datetime): Timestamp when the webhook subscription was last updated (UTC).
- `disabledReason` (string, nullable): Reason why the webhook was automatically disabled (if IsActive is false).
- `secret` (string, nullable): Secret key for HMAC-SHA256 signature verification.
Only returned on creation or secret regeneration — never exposed again for security.
- `isTestMode` (boolean): True when the subscription has `DataClassification.Test` classification;
false for all other classifications (Production, Demo).
Computed as `Classification != DataClassification.Production`.

```json
[
  {
    "id": "3f2b6c1e-8a4d-4b7f-9c2e-5d1a0b9e7f31",
    "url": "https://app.debitura.com/…",
    "events": [
      "string"
    ],
    "isActive": true,
    "createdUtc": "2026-10-01T14:05:00Z",
    "updatedUtc": "2026-10-01T14:05:00Z",
    "disabledReason": null,
    "secret": "string",
    "isTestMode": true
  }
]
```

### Response 401

API key is missing or invalid

<a id="create-a-new-webhook-subscription"></a>

## Create a new webhook subscription

`POST /v1/Webhooks`

Creates webhook subscription for real-time event notifications.

**Available Events:**
- `client.onboarding.poa_signed` - Client signed Power of Attorney
- `client.onboarding.contract_signed` - Client signed Service Delivery Agreement
- `client.linked` - Client successfully linked to your account
- `client.link_declined` - Client declined to link
- `client.link_requested` - 409 link request created (awaiting end-user approval)
- `client.link_expired` - 409 link request reached its TTL without approval/decline
- `case.created` - Collection case created for linked client
- `case.updated` - Collection case lifecycle changed (e.g., Active → Closed)
- `case.closed` - Collection case closed (terminal state)
- `cases.replay_failed` - A stored case payload failed to create during 409 carry-through (retry via the Customer API)

**Security:** Response includes Base64-encoded signing secret (shown only once). Store it to verify HMAC-SHA256 signatures on deliveries.

**Requirements:** HTTPS URL required (HTTP, localhost, and private IPs rejected). Deliveries retry with exponential backoff (8 attempts). Webhook auto-disables after max failures.

### Request body (application/json)

- `url` (string, required): The HTTPS URL where webhook events will be delivered.
Must be a valid HTTPS URL.
  Max 800 characters; URL.
- `events` (array of strings, required): Array of event types to subscribe to.
- `isTestMode` (boolean): When true, the subscription is created with `DataClassification.Test`,
meaning it will only receive events for test-classified data.
Defaults to false (Production classification).

```json
{
  "url": "https://example.com/webhooks/debitura",
  "events": [
    "string"
  ]
}
```

### Response 200

Webhook created successfully

- `id` (uuid): Unique identifier for the webhook subscription.
- `url` (string, nullable): The HTTPS URL where webhook events will be delivered.
- `events` (array of strings, nullable): Array of event types this subscription is interested in.
- `isActive` (boolean): Whether this webhook subscription is active.
- `createdUtc` (datetime): Timestamp when the webhook subscription was created (UTC).
- `updatedUtc` (datetime): Timestamp when the webhook subscription was last updated (UTC).
- `disabledReason` (string, nullable): Reason why the webhook was automatically disabled (if IsActive is false).
- `secret` (string, nullable): Secret key for HMAC-SHA256 signature verification.
Only returned on creation or secret regeneration — never exposed again for security.
- `isTestMode` (boolean): True when the subscription has `DataClassification.Test` classification;
false for all other classifications (Production, Demo).
Computed as `Classification != DataClassification.Production`.

```json
{
  "id": "3f2b6c1e-8a4d-4b7f-9c2e-5d1a0b9e7f31",
  "url": "https://app.debitura.com/…",
  "events": [
    "string"
  ],
  "isActive": true,
  "createdUtc": "2026-10-01T14:05:00Z",
  "updatedUtc": "2026-10-01T14:05:00Z",
  "disabledReason": null,
  "secret": "string",
  "isTestMode": true
}
```

### Response 400

Invalid request (validation errors)

- `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 401

API key is missing or invalid

<a id="get-a-specific-webhook-by-id"></a>

## Get a specific webhook by ID

`GET /v1/Webhooks/{id}`

Returns webhook configuration including URL, events, active status, and DisabledReason if auto-disabled. Secret is never included (only shown during creation/regeneration).

### Path parameters

- `id` (uuid, required): 

### Response 200

Webhook details

- `id` (uuid): Unique identifier for the webhook subscription.
- `url` (string, nullable): The HTTPS URL where webhook events will be delivered.
- `events` (array of strings, nullable): Array of event types this subscription is interested in.
- `isActive` (boolean): Whether this webhook subscription is active.
- `createdUtc` (datetime): Timestamp when the webhook subscription was created (UTC).
- `updatedUtc` (datetime): Timestamp when the webhook subscription was last updated (UTC).
- `disabledReason` (string, nullable): Reason why the webhook was automatically disabled (if IsActive is false).
- `secret` (string, nullable): Secret key for HMAC-SHA256 signature verification.
Only returned on creation or secret regeneration — never exposed again for security.
- `isTestMode` (boolean): True when the subscription has `DataClassification.Test` classification;
false for all other classifications (Production, Demo).
Computed as `Classification != DataClassification.Production`.

```json
{
  "id": "3f2b6c1e-8a4d-4b7f-9c2e-5d1a0b9e7f31",
  "url": "https://app.debitura.com/…",
  "events": [
    "string"
  ],
  "isActive": true,
  "createdUtc": "2026-10-01T14:05:00Z",
  "updatedUtc": "2026-10-01T14:05:00Z",
  "disabledReason": null,
  "secret": "string",
  "isTestMode": true
}
```

### Response 401

API key is missing or invalid

### Response 404

Webhook not found or does not belong to this 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/…"
    }
  ]
}
```

<a id="update-an-existing-webhook-subscription"></a>

## Update an existing webhook subscription

`PUT /v1/Webhooks/{id}`

Updates webhook URL, events, or active status. Set RegenerateSecret=true to rotate signing secret (returned in response). Use IsActive=true to re-enable auto-disabled webhooks after fixing delivery issues. Secret only included if RegenerateSecret=true.

### Path parameters

- `id` (uuid, required): 

### Request body (application/json)

- `url` (string, nullable): The new HTTPS URL where webhook events will be delivered.
Optional — only provide if changing the URL.
  Max 800 characters; URL.
- `events` (array of strings, nullable): Updated list of event types to subscribe to.
Optional — only provide if changing the events.
Note: Not supported by the ExternalCustomerAPI — that endpoint returns 400 if this field is set.
- `isActive` (boolean, nullable): Set to true to enable the webhook, false to disable it.
Optional — only provide if changing the active status.
- `regenerateSecret` (boolean): Set to true to regenerate the webhook secret.
A new secret will be returned in the response.
- `isTestMode` (boolean, nullable): When set, updates the classification of the subscription.
True maps to `DataClassification.Test`; false maps to `DataClassification.Production`.
Omit to leave the current classification unchanged.

```json
{}
```

### Response 200

Webhook updated successfully

- `id` (uuid): Unique identifier for the webhook subscription.
- `url` (string, nullable): The HTTPS URL where webhook events will be delivered.
- `events` (array of strings, nullable): Array of event types this subscription is interested in.
- `isActive` (boolean): Whether this webhook subscription is active.
- `createdUtc` (datetime): Timestamp when the webhook subscription was created (UTC).
- `updatedUtc` (datetime): Timestamp when the webhook subscription was last updated (UTC).
- `disabledReason` (string, nullable): Reason why the webhook was automatically disabled (if IsActive is false).
- `secret` (string, nullable): Secret key for HMAC-SHA256 signature verification.
Only returned on creation or secret regeneration — never exposed again for security.
- `isTestMode` (boolean): True when the subscription has `DataClassification.Test` classification;
false for all other classifications (Production, Demo).
Computed as `Classification != DataClassification.Production`.

```json
{
  "id": "3f2b6c1e-8a4d-4b7f-9c2e-5d1a0b9e7f31",
  "url": "https://app.debitura.com/…",
  "events": [
    "string"
  ],
  "isActive": true,
  "createdUtc": "2026-10-01T14:05:00Z",
  "updatedUtc": "2026-10-01T14:05:00Z",
  "disabledReason": null,
  "secret": "string",
  "isTestMode": true
}
```

### Response 400

Invalid request (validation errors)

- `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 401

API key is missing or invalid

### Response 404

Webhook not found or does not belong to this 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/…"
    }
  ]
}
```

<a id="delete-a-webhook-subscription"></a>

## Delete a webhook subscription

`DELETE /v1/Webhooks/{id}`

Permanently deletes webhook subscription. Cannot be undone. Consider setting IsActive=false to temporarily disable instead. Delivery history is lost after deletion.

### Path parameters

- `id` (uuid, required): 

### Response 204

Webhook deleted successfully

### Response 401

API key is missing or invalid

### Response 404

Webhook not found or does not belong to this 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/…"
    }
  ]
}
```

<a id="trigger-a-test-webhook-event-test-environment-only"></a>

## Trigger a test webhook event (test environment only)

`POST /v1/Webhooks/test`

Triggers a realistic webhook delivery through the real pipeline (queue → dispatcher → HMAC-signed HTTP delivery).

⚠️ **TEST ENVIRONMENT ONLY** - Returns 403 in production. Use testreferral-api.debitura.com for testing.

**How it works:**
- Looks up real entity data (case or client link) to construct a realistic payload
- Publishes through the same pipeline as production events (signature verification, retries, etc.)
- Returns immediately after enqueueing — delivery is async via Azure Queue

**Case events** (`case.created`, `case.updated`, `case.closed`):
- Requires `caseId` — must be a real case belonging to a linked client
- For `case.updated`: optionally provide `oldLifecycle` and `newLifecycle` (defaults to current → Closed)
- For `case.closed`: optionally provide `closeCode` and `closeComment` (defaults to Paid)

**Client events** (`client.linked`, `client.link_declined`, `client.link_requested`, `client.link_expired`, `client.onboarding.poa_signed`, `client.onboarding.contract_signed`):
- Requires `externalTenantId` — must be an active client link belonging to your account

### Request body (application/json)

- `eventType` (string, required): The webhook event type to trigger (e.g. "case.updated", "client.linked")
- `caseId` (uuid, nullable): Required for case.created, case.updated, and case.closed events
- `collectionRequestId` (uuid, nullable): Required for collection_request.updated.
- `externalTenantId` (string, nullable): Required for client.* events (client.linked, client.link_declined, client.onboarding.*)
- `oldLifecycle` (string, nullable): Optional override for case.updated: the "from" lifecycle (defaults to current case lifecycle)
- `newLifecycle` (string, nullable): Optional override for case.updated: the "to" lifecycle (defaults to "Closed")
- `closeCode` (string, nullable): Optional override for case.closed: the close code (defaults to "Paid")
- `closeComment` (string, nullable): Optional override for case.closed: a close comment

```json
{
  "eventType": "string"
}
```

### Response 200

Test event enqueued successfully

- `eventType` (string, nullable): 
- `enqueuedCount` (integer): 
- `message` (string, nullable): 

```json
{
  "eventType": "string",
  "enqueuedCount": 42,
  "message": "Payment plan agreed with the debtor."
}
```

### Response 400

Invalid request (missing required fields or invalid event type)

- `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 401

API key is missing or invalid

### Response 403

Endpoint not available in production environment

- `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 or client link 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/…"
    }
  ]
}
```
