The firm's clients
GET /v1/advisor/clients lists every client of the firm whose connection you
hold, whether or not the client keeps its books in LedgerBee. It needs a firm
token carrying advisor-clients-read. The full schema is in the
API Reference.
Code
Query parameters
| Parameter | Default | Notes |
|---|---|---|
page | 1 | 1-indexed. |
limit | 50 | Clients per page, 1 to 100. |
updatedAtFrom | — | Only clients added to the firm, or changed, at or after this instant. A calendar date (2026-10-01, read as midnight UTC) or a date-time with a time zone (2026-10-01T09:30:00Z, 2026-10-01T11:30:00+02:00). A date-time without a zone is refused. |
Response
Code
Clients are sorted by name, then by companyNumber. The list is always
paginated; request pages until page reaches totalPages.
| Field | Meaning |
|---|---|
id | The id of the firm's own record of the client when the firm keeps one, otherwise the id of the client's LedgerBee company. A client first listed under its company id takes its record's id once the firm records it. |
companyNumber | The client's company number (for a Danish company, its CVR), or null. Compare it with spaces and dashes removed. Name the client by it when you deliver data about it. |
productionUnitNumber | The P-number of the office the client is, 10 digits, when the client is one office of a company; null for the whole company. Two offices of one company are two clients with the same companyNumber. |
externalClientNumber | The firm's own client number, when it keeps one. |
onLedgerBee | true while the client keeps its books in LedgerBee; false for a client the firm tracks that does not, or that has stopped. |
updatedAt | The latest of: when the client was added to the firm, when the firm's record of it last changed, and when the client's own company last changed. |
Key your copy on companyNumber and productionUnitNumber together, not on
id: the same client can change id, and a key on companyNumber alone merges
the offices of one company into one client. A client with no company number
(null) has only its id to key on. That id is its LedgerBee company's, and
it stays put until the client has a company number, because the firm keeps its
own record of a client only under one. When a company number appears, move that
client to the companyNumber and productionUnitNumber key.
Keeping a copy in sync
- Note the current time, then page through the whole list without
updatedAtFrom. - On each later run, note the time again and send the time you noted on the
previous run as
updatedAtFrom. Upsert each client bycompanyNumberandproductionUnitNumber, or byidwhen it has no company number. - Run a full listing now and then. Removals are not reported, so a client missing from a full listing has left the firm.
updatedAt moves on any change to the client's company, so an incremental
listing can return a client whose listed fields are unchanged. Each page is
computed when you request it, so a client added or removed while you page can
shift a later page by one position and skip a client. An incremental run does
not bring back a skipped client that has not changed since, so the full listing
in step 3 is what catches it.
Errors
| Condition | What you observe | Fix |
|---|---|---|
| No token, or an expired or invalid one | 401, code: "UNAUTHORIZED" | Refresh the token, or reconnect |
| The connection ended | 401, details.reason grant_revoked or consenting_user_inactive | Reconnect with a firm admin; see how a connection ends |
| An API key or a company's token | 403, code: "PUBLIC_API_HOLDER_MISMATCH", details: { "required": "advisor", "actual": "company" } | Use a firm token |
The token lacks advisor-clients-read | 403, code: "INSUFFICIENT_PERMISSIONS", WWW-Authenticate with error="insufficient_scope" | Reconnect with the scope |
updatedAtFrom without a time zone, or not a date | 400, code: "SHARED_VALIDATION_FAILED" | Send YYYY-MM-DD or a date-time with Z or an offset |
page below 1, or limit outside 1–100 | 400, code: "SHARED_VALIDATION_FAILED" | Correct the parameter |