---
title: "Payments, the bank feed and this month’s collection status"
method: GET
path: "/api/v1/payments"
tags: ["Money"]
---

# Payments, the bank feed and this month’s collection status

`GET /api/v1/payments`

## Request

- Base URL: `http://localhost:5180`
- URL: `http://localhost:5180/api/v1/payments`
- Auth: API key in cookie `better-auth.session_token`

One page of each list, in primary key order. `limit` and `offset` move the window on all four at once, and `totals` says how many of each exist. `unmatched` and `collection` are counted over everything on file, never over the page, so a badge and a collection rate never shrink because a client asked for fewer rows. Every amount is integer cents. A match below the auto-accept threshold sits in the review queue rather than posting, so a low `confidence` here is a decision still waiting on someone.

## Query parameters

- `limit` integer
- `offset` integer

## Response `200`

Payments, reconciliation and collection.

- object
  - `ok` unknown, required
  - `data` object, required
    - `collection` object, required: Where this month stands against what was due, read over the whole month rather than over a page.
      - `expected` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `collected` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `outstanding` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `rate` number, nullable, required: collected ÷ expected, 0–1. Null when nothing was due, because a share of nothing is not a figure.
      - `invoiceCount` number, required
      - `paidCount` number, required
      - `overdueCount` number, required: Notices whose grace days are over and whose bank has reported past the due date. One not seen yet is never counted.
      - `allInBank` boolean, required: True when every payment behind what was collected came off a bank movement. False when nothing was collected.
    - `payments` object[], required
      - `id` string, required: Stable record id, e.g. `lse_012`.
      - `teamId` string, required: Stable record id, e.g. `lse_012`.
      - `method` string, required
      - `amount` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `currency` string, required
      - `receivedOn` string, required: A calendar date, `YYYY-MM-DD`.
      - `allocations` object[], required
        - `invoiceId` string, required: Stable record id, e.g. `lse_012`.
        - `amount` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `unallocated` integer, required: Money received but not yet matched against an invoice.
      - `bankTransactionId` string: The bank movement this payment came off. Absent for one recorded by hand, which is why `collection.allInBank` can be false.
    - `accounts` object[], required: The accounts the feed lands in. A deposit escrow balance is held money, never income.
      - `id` string, required: Stable record id, e.g. `lse_012`.
      - `teamId` string, required: Stable record id, e.g. `lse_012`.
      - `label` string, required
      - `iban` string, required
      - `bic` string
      - `currency` string, required
      - `purpose` 'operating' | 'deposit_escrow' | 'reserve' | 'personal', required: Deposits sit in a blocked escrow account, so their balance is never treated as income.
      - `balance` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `lastSyncedAt` string: ISO 8601 timestamp.
    - `transactions` object[], required: The bank feed as imported, raw description and all, which is what fuzzy matching works on.
      - `id` string, required: Stable record id, e.g. `lse_012`.
      - `bankAccountId` string, required: Stable record id, e.g. `lse_012`.
      - `date` string, required: A calendar date, `YYYY-MM-DD`.
      - `valueDate` string: A calendar date, `YYYY-MM-DD`.
      - `amount` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `currency` string, required
      - `counterpartyName` string
      - `counterpartyIban` string
      - `description` string, required: The raw free text off the bank statement. This is what fuzzy matching works on.
      - `structuredRef` string
      - `direction` 'in' | 'out', required
      - `status` 'unmatched' | 'matched' | 'partially_matched' | 'ignored' | 'suspense', required
      - `matchId` string: Stable record id, e.g. `lse_012`.
      - `importBatchId` string: Stable record id, e.g. `lse_012`.
      - `externalId` string: The bank’s own id for the movement, where the feed gives one. A duplicate is judged on it first.
      - `bankReference` string: The reference the bank printed on the statement line, where it printed one.
      - `origin` 'manual': Set on a movement the owner typed in rather than one a statement or a bank brought.
      - `sequence` integer: Its place among the movements booked on the same day, as the statement printed them.
      - `balanceAfter` integer: The account balance once this movement had landed, in cents.
      - `balanceSource` 'verified' | 'computed': `verified` was printed by the bank and is never overwritten. `computed` is worked out from the movements around it and is recomputed whenever they change.
      - `expectedBalanceAfter` integer: What the movement before it and this amount add up to. A verified balance that differs is where a movement went missing.
    - `matches` object[], required: What was matched to what, with the confidence and the evidence behind each one.
      - `id` string, required: Stable record id, e.g. `lse_012`.
      - `bankTransactionId` string, required: Stable record id, e.g. `lse_012`.
      - `paymentId` string: Stable record id, e.g. `lse_012`.
      - `invoiceIds` string[], required
      - `expenseId` string: The cost this outbound movement paid, where it paid one.
      - `supplierInvoiceId` string: The supplier invoice this outbound movement settled, where it settled one.
      - `mortgageId` string: The loan this outbound movement repaid an instalment of, where it repaid one.
      - `confidence` number, required: 0 to 1. Below the auto-accept threshold the match lands in the review queue instead of posting.
      - `reasons` string[], required: Why the two were matched, in the order the evidence was found.
      - `status` 'suggested' | 'accepted' | 'rejected' | 'needs_review', required
      - `explanation` string, required: The match in plain words, so accepting it is an informed decision.
      - `allocations` object[]: The split as it was actually applied, kept so reversing the match puts back exactly what it took.
        - `invoiceId` string, required: Stable record id, e.g. `lse_012`.
        - `amount` integer, required: Money, always in integer cents. €1,250.00 is 125000.
      - `provenance` object, required
        - `actor` object, required
          - `kind` 'owner' | 'ai' | 'tenant' | 'contractor' | 'system' | 'channel', required: `ai` is Dardaris acting on the owner’s behalf. Everything it touches is marked.
          - `id` string: Stable record id, e.g. `lse_012`.
          - `name` string, required
        - `at` string, required: ISO 8601 timestamp.
        - `workflowRunId` string: Set when an automated run produced this, linking the record back to the run.
        - `reasoning` string: The rationale the AI recorded at the moment it acted.
    - `unmatched` number, required: How many transactions are still unmatched, across the whole feed and not just this page. This is the count the navigation badge wears.
    - `limit` number, required: The page size this response was actually read at, which is `limit` capped at 200.
    - `offset` number, required: The offset each list was read at.
    - `totals` object, required: How many rows exist of each, not how many came back. Every one of them is reachable through `offset`.
      - `payments` number, required
      - `accounts` number, required
      - `transactions` number, required
      - `matches` number, required
  - `meta` object, required
    - `requestId` string, required: Echoed in the x-request-id header. Quote it in a bug report.

## Other responses

- `400`: `limit` or `offset` is out of range.

---

[API](https://skmtc.dev/dardaris/apis/dardaris-api.md) · [All operations](https://skmtc.dev/dardaris/apis/dardaris-api/llms.txt) · [OpenAPI document](https://skmtc.dev/dardaris/apis/dardaris-api/revisions/4aff33835c73?raw)
