> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.debbiecollect.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Law firm systems

> Integrating a law firm case management system with Debbie

This guide describes how a law firm case management system (a practice or matter management system) integrates with Debbie, so that debt collection cases created by the lawyer are replicated into Debbie, handled through a collection workflow, and settled back to the law firm system.

The integration is built entirely on the RESTful JSON API and webhooks. It is deliberately small: four endpoints for pushing data into Debbie, and a handful of webhooks for getting financial events back.

## How the two systems divide responsibility

The law firm system stays the system of record for the matter — the client relationship, the parties, the invoicing of legal work. Debbie becomes the system of record for the collection process — the workflow, the letters, the interest calculation, the fees, the payment plans, the court steps and the settlement of the creditor.

<img src="https://mintcdn.com/debbie-bd9dd858/c4KJPAFU082ys87I/images/object-model.svg?fit=max&auto=format&n=c4KJPAFU082ys87I&q=85&s=3deaf9f2abf15b1a9968dcb00030c26e" width="859" height="407" data-path="images/object-model.svg" />

Data flows in both directions:

| Direction                | Mechanism      | What it carries                                                                                                    |
| ------------------------ | -------------- | ------------------------------------------------------------------------------------------------------------------ |
| Law firm system → Debbie | REST endpoints | Creditors, customers (parties), cases with their financial entries, and deposits registered in the law firm system |
| Debbie → law firm system | Webhooks       | Fees imposed during collection, case status changes, and how settled deposits should be distributed                |

<Tip>
  Push data to Debbie synchronously as part of the user's action in the law firm
  system where you can, but always make the calls retryable. Every write
  endpoint accepts an `Idempotency-Key`, so a failed request can safely be
  replayed from a queue.
</Tip>

## Before you start

1. **Get a sandbox tenant.** Contact the Debbie team. Every endpoint is scoped by `tenantId`, which is part of the path, so a sandbox and a production tenant differ only by that id and the API key.
2. **Create an API key.** In the platform, go to *Developers → API*, name the key and grant the scopes listed under [Scopes](#scopes). Authenticate with `Authorization: Bearer {token}` — see [Authentication](/api-reference/authentication).
3. **Subscribe to webhooks.** Under *Developers → Webhooks*. Register the endpoint in your system that should receive the events listed under [Webhooks back to the law firm system](#webhooks-back-to-the-law-firm-system).

## Identifiers to store on both sides

Getting the identifier mapping right is the single most important part of the integration. Decide up front which id lives where, and persist it.

| Store in the law firm system | Where it comes from                     | Used for                                        |
| ---------------------------- | --------------------------------------- | ----------------------------------------------- |
| `creditorId`                 | `POST /creditors` response `id`         | Creating customers and cases for that creditor  |
| `customerId`                 | `POST /customers` response `customerId` | Creating cases for that party                   |
| `caseId` (uuid)              | `POST /cases` response `id`             | Registering deposits and reading the case later |
| `caseSeqId` (number)         | `POST /cases` response `caseSeqId`      | Deep-linking a user into Debbie                 |

| Store in Debbie                        | Field                             | Used for                                                                         |
| -------------------------------------- | --------------------------------- | -------------------------------------------------------------------------------- |
| The law firm's own case number         | `customJournalNumber` on the case | Making the case number identical in both systems                                 |
| The law firm's own creditor number     | `id` on the creditor              | Reconciling the creditor between the two systems — it is returned as `reference` |
| The law firm's own client/party number | `referenceId` on the customer     | Looking the customer up again via `GET /customers/by-reference-id/{referenceId}` |
| A link back to the law firm system     | `erpLink` on the creditor         | Letting a Debbie caseworker jump to the party in the law firm system             |

Deep-link from the law firm system into Debbie with the sequential case id:

```
https://app.debbiecollect.com/cases/{caseSeqId}
```

<Warning>
  Always set `customJournalNumber` when you create the case. Without it Debbie
  falls back to its own sequential journal number, and the case will be
  referenced by two different numbers in the two systems — including in letters
  and court documents sent to the debtor.
</Warning>

## 1. Create the creditor

A creditor is the party the money is owed to — the law firm's client. Only create the creditors that actually have collection cases.

Before creating a case, check whether the creditor already exists in Debbie. If it does not, create it and store the returned `id` on the client record in the law firm system.

```json POST /v1/{tenantId}/creditors theme={null}
{
  "id": "CLIENT-4471",
  "name": "Nordisk Byg A/S",
  "centralRegisterId": "DK40125949",
  "isCompany": true,
  "vatRegistered": true,
  "address": {
    "address": "Havnegade 12",
    "zipcode": "1058",
    "city": "København K",
    "country": "DK"
  },
  "erpLink": "https://your-system.example.com/parties/{{customerReferenceId}}",
  "bankAccountDetails": {
    "type": "DANISH",
    "registrationNumber": "1234",
    "accountNumber": "12345678"
  }
}
```

`id` is your own creditor number, returned as `reference` on subsequent reads. `bankAccountDetails` is what Debbie pays out to when the creditor is settled, so include it if the law firm system holds it. `erpLink` supports the `{{customerReferenceId}}` placeholder, which Debbie substitutes with the customer's `referenceId` — giving the caseworker a one-click jump to the right party in the law firm system.

<Card horizontal title="API reference: Create creditor">
  See [POST Create creditor](/api-reference/endpoints/creditors/create) for full
  details.
</Card>

## 2. Create the customer and its parties

A case is never created directly on a creditor — it hangs off a *customer*. A customer represents the creditor's relationship with the other side of the matter, and holds one or more contacts, called users.

Create the customer with the debtor, plus any other party the law firm knows about, before creating the case. The creditor is passed as a query parameter.

```json POST /v1/{tenantId}/customers?creditorId={creditorId} theme={null}
{
  "isCompany": false,
  "referenceId": "PARTY-99120",
  "users": [
    {
      "relation": "debtor",
      "contact": true,
      "lang": "da",
      "details": {
        "name": "Mette Jensen",
        "cpr": "0101801234",
        "email": "mette@example.com",
        "phone": { "locale": "45", "number": "12345678" },
        "address": {
          "address": "Søndergade 5, 2. th",
          "zipcode": "8000",
          "city": "Aarhus C",
          "country": "DK"
        }
      }
    }
  ]
}
```

* `relation` is `debtor` for the party who owes the money, and `alternative-contact` for anyone else on the matter — a lawyer, a guardian, an administrator, a parent company contact.
* `contact: true` marks the user Debbie addresses its communication to.
* `referenceId` is your own party number. Use `GET /customers/by-reference-id/{referenceId}?creditorId={creditorId}` to look the customer up again instead of keeping a mapping table.

Parties discovered after the case was created are added with `POST /customers/{customerId}/users`.

<Card horizontal title="API reference: Create customer">
  See [POST Create customer](/api-reference/endpoints/customers/create) for full
  details.
</Card>

## 3. Create the case with its financial entries

The case is created in the law firm system and replicated into Debbie. Send the financial entries of the matter along with it as case vouchers, so the case arrives in Debbie with a correct balance.

```json POST /v1/{tenantId}/cases theme={null}
{
  "customerId": "{customerId}",
  "currency": "DKK",
  "customJournalNumber": {
    "type": "CUSTOM_STRING",
    "journalNumber": "2026-00417"
  },
  "caseVouchers": [
    {
      "voucherTypeId": "{invoiceVoucherTypeId}",
      "referenceId": "F-100241",
      "amount": -450000,
      "currency": "DKK",
      "date": "2026-05-02",
      "dueDate": "2026-05-16",
      "source": "CREDITOR",
      "uniqueId": "F-100241",
      "interest": 0.1225,
      "interestStartDate": "2026-05-17"
    }
  ]
}
```

A few things to get right:

* **Amounts are integers in the minor unit, and debt is negative.** `-450000` is a debt of 4,500.00 DKK; a positive amount is a credit note or a deposit.
* **`voucherTypeId` comes from `GET /voucher-types`.** Fetch the list once and cache it — the invoice, reminder fee and deposit types you need are stable per tenant.
* **`source` is `CREDITOR`** for everything the law firm imposes before handover. `COLLECTOR` is reserved for what the collection agency imposes.
* **Set `uniqueId`** to your own invoice number. It is unique per tenant and stops the same voucher from being created twice if a request is replayed.
* **`interest` is a decimal fraction** — `0.1225` is 12.25% per year — and applies from `interestStartDate`.

The response gives you both ids to store:

```json theme={null}
{ "id": "b2b0…", "caseSeqId": 10427 }
```

<Card horizontal title="API reference: Create case">
  See [POST Create case](/api-reference/endpoints/cases/create) for full details.
</Card>

<Tip>
  If the law firm system does not model the matter as a case at all — for
  example when it only holds open invoices — you can skip this step and post
  vouchers straight onto the customer with [POST Add case vouchers on
  customer](/api-reference/endpoints/customers/add-case-vouchers). Debbie then
  decides itself whether to open a new case or extend an existing one.
</Tip>

## 4. Register deposits paid to the law firm

Payments the debtor makes directly to the law firm's client account must be replicated into Debbie, so the balance is correct and so the collection process — reminders, payment plans, court steps, and any reply to the court — reflects what has actually been paid.

```json POST /v1/{tenantId}/case-vouchers/{caseId} theme={null}
{
  "voucherTypeId": "{depositVoucherTypeId}",
  "amount": 100000,
  "currency": "DKK",
  "date": "2026-06-04",
  "source": "CREDITOR",
  "uniqueId": "BANK-2026-06-04-0093"
}
```

`source: "CREDITOR"` marks the deposit as paid directly to the creditor rather than collected by Debbie — this is what makes the settlement in step 5 come out right. Set `uniqueId` from the bank transaction id so a replay cannot double-book the payment.

By default Debbie distributes the amount across the case's vouchers using the tenant's distribution rules. To settle specific invoices instead, send `distribute` as an array of `{ "value": { "amount": 50000, "caseVoucherReferenceId": "F-100241" } }` entries — one per voucher, keyed by your invoice number (`caseVoucherReferenceId`) or by `caseVoucherId`. The distributed amounts must sum to the deposit's `amount`.

<Card horizontal title="API reference: Add case voucher">
  See [POST Add case voucher](/api-reference/endpoints/case-vouchers/create) for
  full details.
</Card>

## 5. Receive fees, status changes and settlements

Everything that happens after handover is reported back over webhooks.

### Fees imposed during collection

`case-vouchers.create` fires for every voucher created in Debbie — collection fees, court fees, interest entries and deposits registered by Debbie. Filter on `data.source === "COLLECTOR"` to pick out what Debbie imposed, and use `data.category` (`fee`, `courtcost`, `interest`, `collectioncommission`, …) to book it in the law firm system.

`case-vouchers.update` and `case-vouchers.delete` fire when a voucher is later changed or removed — handle them, or the balance in the two systems will drift.

### Case status

`cases.update` reports changes to the case, including status transitions. On a transition `data.status` is set to the new status — `PENDING`, `VERIFIED` or `ENDED` — and when the case ends, `data.endReasonId` and `data.handle` tell you *why* — paid in full, written off, withdrawn — which is usually what the law firm system needs to close the matter.

`cases.merge` fires when Debbie merges two cases for the same debtor. If the law firm system holds one matter per Debbie case, this is the event that tells you two of your matters are now handled as one.

### Settlement of the creditor

When creditors are settled in Debbie, a billing is created and `billings.create` fires with a `billingId`. Call:

```
GET /v1/{tenantId}/billings/{billingId}/deposit-distribution
```

to get, per deposit in the billing, how the amount was split. The response is paged as `items` plus `meta` — 25 deposits per page by default — so page through it with `page` and `pageSize`. It reports which case and customer each deposit belongs to, which case vouchers it was distributed to, how much of it is `overpayment`, and which of the vouchers carry `collectionCommission`. This is the breakdown the law firm system needs to book revenue, overpayments and the amount payable to the client.

<Note>
  If the law firm registers deposits paid directly to it (step 4), add
  `?includeDepositsWithSourceCreditor=true`. Without it, the collection
  commission charged on those direct payments is reported as a separate fee on
  the billing rather than as part of the deposit's distribution.
</Note>

`payouts.create` then reports the actual payouts, with `type` telling you whether it is a `CREDITOR_RECEIVABLES` settlement, an `OVERPAYMENT` refund to the debtor, or a `COURT_FEE`, and `caseId` / `caseSequentialId` linking it back to the matter.

## Webhooks back to the law firm system

These are the events a law firm integration normally subscribes to:

| Event                  | Why you want it                                                                                   |
| ---------------------- | ------------------------------------------------------------------------------------------------- |
| `case-vouchers.create` | Fees, interest and deposits imposed in Debbie                                                     |
| `case-vouchers.update` | A voucher amount or date changed                                                                  |
| `case-vouchers.delete` | A voucher was removed                                                                             |
| `cases.update`         | The case changed — a status transition carries the new status and, on ended cases, the end reason |
| `cases.merge`          | Two cases were merged into one                                                                    |
| `billings.create`      | A settlement run completed — fetch the deposit distribution                                       |
| `payouts.create`       | Money was paid out to the creditor or refunded to the debtor                                      |
| `payment-plans.create` | A payment plan was created                                                                        |
| `payment-plans.update` | A payment plan changed — activation, completion and cancellation arrive as a `status` field       |

### Delivery

Every delivery is a `POST` with a JSON body of the shape:

```json theme={null}
{
  "event": "case-vouchers.create",
  "time": "2026-06-04T09:12:44.021Z",
  "data": { "...": "..." }
}
```

* Debbie sends `X-Verification-Token` with the token from your webhook subscription. **Verify it on every request** before acting on the payload.
* Any non-2xx response counts as a failure. The first delivery is attempted immediately; a failure is then retried up to 7 more times with exponential backoff — roughly 1, 3, 8, 21, 55, 149 and 404 minutes after the previous attempt, about eleven hours end to end — so a receiver that is down for most of a day will still catch up.
* Respond quickly and process asynchronously. Acknowledge with 200 as soon as the payload is persisted rather than after your own downstream work has finished.
* Retries mean a delivery can arrive more than once, replayed with an unchanged body. There is no single `data.id` across events, so key the handler on the identifiers each event actually carries: `caseVoucherId` for `case-vouchers.*`, `id` for `billings.create` and `payouts.create`, `caseId` together with `status` for `cases.update`, `fromCaseId` and `toCaseId` for `cases.merge`, and `paymentPlanId` for `payment-plans.*`.

Deliveries can be listed with `GET /webhooks/items`, filtered by `webhookId` and `state`, so the law firm system can reconcile what it received against what Debbie sent. Deliveries that exhausted their retries can be re-sent from *Developers → Webhooks* in the platform.

<Card horizontal title="API reference: Webhooks">
  See [Get webhook items](/api-reference/endpoints/webhooks/get-items) and the
  payload of each event under Webhooks in the API reference.
</Card>

## Scopes

Grant the API key only what the integration uses:

| Scope                                       | Needed for                                                            |
| ------------------------------------------- | --------------------------------------------------------------------- |
| `read:creditors`, `write:creditors`         | Step 1                                                                |
| `read:customers`, `write:customers`         | Step 2                                                                |
| `read:cases`, `write:cases`                 | Step 3                                                                |
| `read:case-vouchers`, `write:case-vouchers` | Steps 3 and 4                                                         |
| `read:voucher-types`                        | Resolving `voucherTypeId`                                             |
| `read:billings`                             | Step 5, the deposit distribution                                      |
| `read:webhooks`, `write:webhooks`           | Inspecting deliveries, and re-sending ones that failed                |
| `read:files`, `write:files`                 | Attaching invoice PDFs to vouchers                                    |
| `write:interactions.create`                 | Posting interactions, see [Optional extensions](#optional-extensions) |

## Optional extensions

Once the core flow runs, these are the usual next steps:

* **Attach documents.** Upload the invoice or contract with `POST /files` and reference it as the `appendix` of the case voucher, so it follows the case into letters and court documents.
* **Register incoming communication.** Post a `POST /interactions` of type `NOTE` or `DEBTOR NOTE` when the debtor contacts the law firm, so the Debbie caseworker sees it on the case.
* **Enrich with custom fields.** Send `properties` on the case or the voucher to carry law-firm-specific data into Debbie's letter templates.

## Checklist before going live

<Steps>
  <Step title="Identifiers are stored on both sides">
    `creditorId`, `customerId`, `caseId` and `caseSeqId` are persisted in the law firm system, and `customJournalNumber` is set on every case.
  </Step>

  <Step title="Every write is replayable">
    `Idempotency-Key` on the request, `uniqueId` on every voucher, and failed calls go to a retry queue rather than being dropped.
  </Step>

  <Step title="The webhook receiver verifies and is idempotent">
    `X-Verification-Token` is checked, the handler tolerates duplicate deliveries, and it responds 200 before doing downstream work.
  </Step>

  <Step title="Deposits flow both ways">
    Payments to the law firm are pushed to Debbie as `source: "CREDITOR"` deposits, and deposits collected by Debbie are booked from `case-vouchers.create`.
  </Step>

  <Step title="Settlement is booked from the deposit distribution">
    `billings.create` triggers a fetch of the deposit distribution, and revenue, overpayments and the creditor payout are booked from it.
  </Step>
</Steps>
