Tolvi Hub
18 operations in the Tolvi API, version 1. Paths are relative to https://api.tolvi.co.uk. Every amount is integer pence.
Get the home page
GET/api/v1/hub/home
- Scopes
clients:read
How many clients the firm has, your work and your meetings today, in one read. A product’s part is null when you can’t use it or the credential has no scope for it. Part of the hub product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (HubHome).
The accountant’s home page in one read. A product’s part is null when this person can’t use it.
| Field | Type | Description |
|---|---|---|
clientsrequired | object (HubClientCounts) | |
clients.activerequired | integer | |
clients.prospectrequired | integer | |
clients.formerrequired | integer | |
workrequired | object (HubWork)nullable | Engagements where you are on the team, from Working Papers. |
work.yourTurnrequired | integer | Your turn, due soon: the Work queue’s to-do view. |
work.toReviewrequired | integer | Waiting for your review. |
work.overduerequired | integer | |
work.dueIn30Daysrequired | integer | |
work.nextDeadlinesrequired | array of HubDeadline | The next five filing deadlines. |
work.nextDeadlines[].engagementIdrequired | string (uuid) | |
work.nextDeadlines[].clientIdrequired | string (uuid) | |
work.nextDeadlines[].clientNamerequired | string | |
work.nextDeadlines[].periodEndrequired | string (date) | example "2026-03-31" |
work.nextDeadlines[].dueDaterequired | string (date) | example "2026-03-31" |
work.nextDeadlines[].daysLeftrequired | integer | Days from today to the deadline; negative when overdue. |
work.nextDeadlines[].stageNamerequired | string | |
suite | object (HubSuite) | Your work across every product you can use. Counts are of work you answer for. |
suite.productsrequired | array of WorkItemProduct | The products counted: those you can use. One of: |
suite.yourTurnrequired | integer | You act next. |
suite.toReviewrequired | integer | Waiting for your review. |
suite.overduerequired | integer | |
suite.dueIn30Daysrequired | integer | |
suite.nextDeadlinesrequired | array of SuiteDeadline | The next five deadlines, each with its product. |
suite.nextDeadlines[].productrequired | string (WorkItemProduct) | The products counted: those you can use. One of: |
suite.nextDeadlines[].itemIdrequired | string (uuid) | |
suite.nextDeadlines[].clientIdrequired | string (uuid) | |
suite.nextDeadlines[].clientNamerequired | string | |
suite.nextDeadlines[].periodLabelrequired | string | example "2025/26" |
suite.nextDeadlines[].stageLabelrequired | string | |
suite.nextDeadlines[].kindrequired | string (WorkDeadlineKind) | One of: |
suite.nextDeadlines[].labelrequired | string | |
suite.nextDeadlines[].dueDaterequired | string (date) | example "2026-03-31" |
suite.nextDeadlines[].daysLeftrequired | integer | Days from today; negative when overdue. |
meetingsTodayrequired | array of HubMeetingnullable | Note-takers you sent to meetings today (UK time). Null without Meetings. |
meetingsToday[].idrequired | string (uuid) | |
meetingsToday[].titlerequired | string | |
meetingsToday[].clientIdrequired | string (uuid)nullable | |
meetingsToday[].clientNamerequired | stringnullable | |
meetingsToday[].joinAtrequired | string (date-time) | |
meetingsToday[].statusrequired | string |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
List work across the products
GET/api/v1/hub/work-items
- Scopes
clients:read
Engagements, self assessment returns, accounts and Company Tax Returns in one list, soonest deadline first. Only products you can use and your credential has a scope for are looked in. Complete work is left out unless you ask for it. Accounts count as complete once approved, because filing at Companies House isn’t recorded. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
limit | query | integer | 1 to 500; default 50 |
cursor | query | string | |
updatedFrom | query | string (date) | Last changed on or after this date. |
openPoints | query | string | true: has open review points. One of: |
atRisk | query | string | true: due within 30 days and not yet in review. One of: |
ownerId | query | string | Who acts next: a person’s id, or none for work nobody holds yet. |
includeCompleted | query | string | One of: |
overdue | query | string | One of: |
dueTo | query | string (date) | Any of its deadlines on or before this date. |
dueFrom | query | string (date) | Any of its deadlines on or after this date. |
clientId | query | string (uuid) | |
q | query | string | Part of the client name. up to 100 characters |
stage | query | string (WorkItemStage) | One of: |
product | query | string (WorkItemProduct) | One of: |
scope | query | string | mine: work you prepare or review, or whose client you answer for. turn: you act next. review: waiting for your review. Left out: all. One of: |
Responses
200 OK, application/json
Body: object (WorkItemPage).
Work across the products you can use, soonest deadline first.
| Field | Type | Description |
|---|---|---|
rowsrequired | array of WorkItem | |
rows[].productrequired | string (WorkItemProduct) | The products counted: those you can use. One of: |
rows[].idrequired | string (uuid) | The engagement, return or set of accounts. |
rows[].clientIdrequired | string (uuid) | |
rows[].clientNamerequired | string | |
rows[].periodLabelrequired | string | example "YE 31 Mar 2026" |
rows[].periodEndrequired | string (date) | example "2026-03-31" |
rows[].dueDaterequired | string (date) | The filing date, by the rule the product uses. example "2026-03-31" |
rows[].daysLeftrequired | integer | Days from today; negative when overdue. |
rows[].deadlinesrequired | array of WorkDeadline | Corporation tax has a payment date as well as a filing date. |
rows[].deadlines[].kindrequired | string (WorkDeadlineKind) | One of: |
rows[].deadlines[].labelrequired | string | example "CT600 filing" |
rows[].deadlines[].daterequired | string (date) | example "2026-03-31" |
rows[].statusrequired | string | The product’s own status. |
rows[].stagerequired | string (WorkItemStage) | One of: |
rows[].stageLabelrequired | string | example "In review" |
rows[].ownerIdrequired | string (uuid)nullable | Who acts next. Null when that is any partner, or nobody yet. |
rows[].ownerNamerequired | stringnullable | |
rows[].openReviewPointsrequired | integer | |
rows[].updatedAtrequired | string (date-time) | |
nextCursorrequired | stringnullable | Opaque cursor for the next page (pass as |
pageSizerequired | integer | The page size that was used. 1 to 100 |
totalsrequired | object (WorkItemTotals) | |
totals.totalrequired | integer | Every row this filter matches, before paging. |
totals.overduerequired | integer | |
totals.dueIn30Daysrequired | integer | |
totals.workingPapersrequired | integer | |
totals.selfAssessmentrequired | integer | |
totals.accountsrequired | integer | |
totals.corporationTaxrequired | integer | |
productsrequired | array of WorkItemProduct | The products looked in: those you can use. One of: |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
List the dashboard widgets you can see
GET/api/v1/hub/widgets
- Scopes
clients:read
The catalogue: each widget’s purpose, where its figures come from, its usual size and who can see it. Widgets for apps you can’t use are left out. Part of the hub product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (HubWidgetCatalogue).
| Field | Type | Description |
|---|---|---|
widgetsrequired | array of HubWidgetDefinition | Only widgets you can see. |
widgets[].keyrequired | string (HubWidgetKey) | One of: |
widgets[].titlerequired | string | |
widgets[].purposerequired | string | |
widgets[].dataSourcerequired | string | |
widgets[].audiencerequired | string | Who can see it. |
widgets[].wrequired | integer | Its usual width, in columns of twelve. |
widgets[].hrequired | integer | Its usual height, in rows. |
widgets[].scopesrequired | array of string | Whose work it can count; the first is the default. Empty when that doesn’t apply. One of: |
widgets[].byProductrequired | boolean | Whether it can be narrowed to one app. |
productsrequired | array of string | The apps whose work you can read. One of: |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Get one widget’s figures
GET/api/v1/hub/widgets/{key}
- Scopes
clients:read
Read from the product that holds them when you ask, so nothing can go stale. Money is in integer pence. Each number says which query on GET /hub/work-items shows the work behind it. Refused with 403 when the widget needs an app or a scope you don’t have. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
keyrequired | path | string | One of: |
product | query | string (WorkItemProduct) | Only this app’s work. Refused where the widget doesn’t offer it. One of: |
scope | query | string (HubWidgetScope) | mine: work you answer for. all: everyone’s. Refused where the widget doesn’t offer it. One of: |
Responses
200 OK, application/json
Body: object (HubWidgetData).
What one widget shows, read from the product that holds it when you ask. Nothing is stored.
| Field | Type | Description |
|---|---|---|
keyrequired | string (HubWidgetKey) | One of: |
asOfrequired | string (date) | example "2026-03-31" |
summaryrequired | string | One sentence saying what it shows: the text alternative for a chart. |
figurerequired | object (HubWidgetFigure)nullable | |
figure.valuerequired | integer | In integer pence when the unit is pence. |
figure.unitrequired | string (HubWidgetFigureUnit) | One of: |
figure.labelrequired | string | |
figure.tonerequired | string (HubWidgetFigureTone) | One of: |
chartrequired | string (HubWidgetChart) | One of: |
barsrequired | array of HubWidgetBar | |
bars[].keyrequired | string | |
bars[].labelrequired | string | |
bars[].valuerequired | integer | |
bars[].filterrequired | object (HubWidgetWorkFilter)nullable | The query on GET /hub/work-items that shows the work behind a number. |
bars[].filter.scope | string (HubWidgetWorkFilterScope) | One of: |
bars[].filter.product | string (WorkItemProduct) | The products counted: those you can use. One of: |
bars[].filter.stage | string (WorkItemStage) | One of: |
bars[].filter.ownerId | string | A person’s id, or none for work nobody holds. |
bars[].filter.dueFrom | string (date) | example "2026-03-31" |
bars[].filter.dueTo | string (date) | example "2026-03-31" |
bars[].filter.overdue | boolean | |
bars[].filter.atRisk | boolean | |
bars[].filter.openPoints | boolean | |
bars[].filter.includeCompleted | boolean | |
bars[].filter.updatedFrom | string (date) | example "2026-03-31" |
bars[].segmentsrequired | array of HubWidgetSegment | |
bars[].segments[].keyrequired | string | |
bars[].segments[].labelrequired | string | |
bars[].segments[].valuerequired | integer | |
bars[].segments[].filterrequired | object (HubWidgetWorkFilter)nullable | The query on GET /hub/work-items that shows the work behind a number. |
bars[].segments[].filter.scope | string (HubWidgetWorkFilterScope) | One of: |
bars[].segments[].filter.product | string (WorkItemProduct) | The products counted: those you can use. One of: |
bars[].segments[].filter.stage | string (WorkItemStage) | One of: |
bars[].segments[].filter.ownerId | string | A person’s id, or none for work nobody holds. |
bars[].segments[].filter.dueFrom | string (date) | example "2026-03-31" |
bars[].segments[].filter.dueTo | string (date) | example "2026-03-31" |
bars[].segments[].filter.overdue | boolean | |
bars[].segments[].filter.atRisk | boolean | |
bars[].segments[].filter.openPoints | boolean | |
bars[].segments[].filter.includeCompleted | boolean | |
bars[].segments[].filter.updatedFrom | string (date) | example "2026-03-31" |
legendrequired | array of HubWidgetLegendEntry | |
legend[].keyrequired | string | |
legend[].labelrequired | string | |
rowsrequired | array of HubWidgetRow | At most twelve. total says how many there are. |
rows[].idrequired | string | |
rows[].titlerequired | string | |
rows[].detailrequired | string | |
rows[].daterequired | string (date)nullable | example "2026-03-31" |
rows[].daysLeftrequired | integernullable | |
rows[].amountPencerequired | integernullable | Integer pence. |
rows[].countrequired | integernullable | |
rows[].linkrequired | object (HubWidgetLink)nullable | What a row or widget opens. |
rows[].link.kindrequired | string (HubWidgetLinkKind) | One of: |
rows[].link.product | string (WorkItemProduct) | The products counted: those you can use. One of: |
rows[].link.id | string (uuid) | |
totalrequired | integer | |
filterrequired | object (HubWidgetWorkFilter)nullable | The work behind the whole widget; null when it isn’t work. |
filter.scope | string (HubWidgetWorkFilterScope) | One of: |
filter.product | string (WorkItemProduct) | The products counted: those you can use. One of: |
filter.stage | string (WorkItemStage) | One of: |
filter.ownerId | string | A person’s id, or none for work nobody holds. |
filter.dueFrom | string (date) | example "2026-03-31" |
filter.dueTo | string (date) | example "2026-03-31" |
filter.overdue | boolean | |
filter.atRisk | boolean | |
filter.openPoints | boolean | |
filter.includeCompleted | boolean | |
filter.updatedFrom | string (date) | example "2026-03-31" |
linkrequired | object (HubWidgetLink)nullable | Where to go for more when it isn’t work. |
link.kindrequired | string (HubWidgetLinkKind) | One of: |
link.product | string (WorkItemProduct) | The products counted: those you can use. One of: |
link.id | string (uuid) | |
noterequired | stringnullable | Something the reader should know, such as what’s left out. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
List dashboards
GET/api/v1/hub/dashboards
- Scopes
clients:read
The presets for the apps you can use, your own and those shared with the firm, with which to open first. A preset’s layout leaves out widgets you can’t see. Part of the hub product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (HubDashboardList).
| Field | Type | Description |
|---|---|---|
dashboardsrequired | array of HubDashboard | Presets for the apps you can use, then your own and those shared with the firm, by name. |
dashboards[].idrequired | string | preset:<key> for a preset, otherwise the dashboard’s id. example "preset:my_work" |
dashboards[].namerequired | string | |
dashboards[].descriptionrequired | stringnullable | |
dashboards[].kindrequired | string (HubDashboardKind) | preset: read only, can be duplicated. private: only its creator sees it. firm: everyone in the firm sees it. One of: |
dashboards[].canEditrequired | boolean | Whether you may change or delete it: its creator, or for a shared one a manager and above. |
dashboards[].minerequired | boolean | |
dashboards[].createdByNamerequired | stringnullable | Who made it; null for a preset or someone who has left. |
dashboards[].layoutrequired | array of HubLayoutItem | |
dashboards[].layout[].widgetrequired | string (HubWidgetKey) | One of: |
dashboards[].layout[].wrequired | integer | Columns of twelve. A phone shows one column. One of: |
dashboards[].layout[].hrequired | integer | Rows of the grid. One of: |
dashboards[].layout[].scope | string (HubWidgetScope) | mine: work you answer for. all: everyone’s. Left out: the widget’s default. One of: |
dashboards[].layout[].product | string (WorkItemProduct) | Only this app’s work. One of: |
dashboards[].updatedAtrequired | string (date-time)nullable | |
defaultIdrequired | string | Which to open: your choice while it’s still there, otherwise the preset for your role. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Save a new dashboard
POST/api/v1/hub/dashboards
- Scopes
clients:read- Access
- A signed-in Tolvi session only, never an API token.
- Retries
- Send an
Idempotency-Keyto make retries safe.
Anyone in the firm can make a dashboard, private or shared with the firm. To duplicate one, send its layout under a new name. Signed-in people only. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
Idempotency-Key | header | string | A unique key (1-255 visible characters) to make retries safe. Replayed for 24 hours. 1 to 255 characters |
Request body
Required. application/json: object (CreateHubDashboard).
| Field | Type | Description |
|---|---|---|
namerequired | string | up to 60 characters |
visibility | string (HubDashboardVisibility) | Left out: private. One of: |
layoutrequired | array of HubLayoutItem | |
layout[].widgetrequired | string (HubWidgetKey) | One of: |
layout[].wrequired | integer | Columns of twelve. A phone shows one column. One of: |
layout[].hrequired | integer | Rows of the grid. One of: |
layout[].scope | string (HubWidgetScope) | mine: work you answer for. all: everyone’s. Left out: the widget’s default. One of: |
layout[].product | string (WorkItemProduct) | Only this app’s work. One of: |
Responses
201 Created, application/json
Body: object (HubDashboard).
A preset, or a dashboard someone saved.
| Field | Type | Description |
|---|---|---|
idrequired | string | preset:<key> for a preset, otherwise the dashboard’s id. example "preset:my_work" |
namerequired | string | |
descriptionrequired | stringnullable | |
kindrequired | string (HubDashboardKind) | preset: read only, can be duplicated. private: only its creator sees it. firm: everyone in the firm sees it. One of: |
canEditrequired | boolean | Whether you may change or delete it: its creator, or for a shared one a manager and above. |
minerequired | boolean | |
createdByNamerequired | stringnullable | Who made it; null for a preset or someone who has left. |
layoutrequired | array of HubLayoutItem | |
layout[].widgetrequired | string (HubWidgetKey) | One of: |
layout[].wrequired | integer | Columns of twelve. A phone shows one column. One of: |
layout[].hrequired | integer | Rows of the grid. One of: |
layout[].scope | string (HubWidgetScope) | mine: work you answer for. all: everyone’s. Left out: the widget’s default. One of: |
layout[].product | string (WorkItemProduct) | Only this app’s work. One of: |
updatedAtrequired | string (date-time)nullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 409 Conflict, 422 Unprocessable content, 429 Too many requests, as problem details (application/problem+json).
Choose your default dashboard
PUT/api/v1/hub/dashboards/default
- Scopes
clients:read- Access
- A signed-in Tolvi session only, never an API token.
A preset or a dashboard you can see. If it later goes, Home opens the preset for your role. Signed-in people only. Part of the hub product: the firm must have it and you must have access to it.
Request body
Required. application/json: object (SetHubDefaultDashboard).
| Field | Type | Description |
|---|---|---|
dashboardrequired | string | preset:<key> or a dashboard’s id. example "preset:deadlines" |
Responses
200 OK, application/json
Body: object (SetHubDefaultDashboard).
| Field | Type | Description |
|---|---|---|
dashboardrequired | string | preset:<key> or a dashboard’s id. example "preset:deadlines" |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Change a dashboard
PATCH/api/v1/hub/dashboards/{id}
- Scopes
clients:read- Access
- A signed-in Tolvi session only, never an API token.
Name, layout or who sees it. Its creator, or for a shared dashboard a manager and above. Others can duplicate it and change their copy. Only its creator can make a shared one private. Signed-in people only. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Request body
Required. application/json: object (UpdateHubDashboard).
Only the fields sent are changed.
| Field | Type | Description |
|---|---|---|
name | string | up to 60 characters |
visibility | string (HubDashboardVisibility) | Left out: private. One of: |
layout | array of HubLayoutItem | |
layout[].widgetrequired | string (HubWidgetKey) | One of: |
layout[].wrequired | integer | Columns of twelve. A phone shows one column. One of: |
layout[].hrequired | integer | Rows of the grid. One of: |
layout[].scope | string (HubWidgetScope) | mine: work you answer for. all: everyone’s. Left out: the widget’s default. One of: |
layout[].product | string (WorkItemProduct) | Only this app’s work. One of: |
Responses
200 OK, application/json
Body: object (HubDashboard).
A preset, or a dashboard someone saved.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Delete a dashboard
DELETE/api/v1/hub/dashboards/{id}
- Scopes
clients:read- Access
- A signed-in Tolvi session only, never an API token.
Its creator, or for a shared dashboard a manager and above. Others can duplicate it and change their copy. Signed-in people only. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
204 No content
Gone.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get one client across the suite
GET/api/v1/clients/{clientId}/overview
- Scopes
clients:read
The record, and what each product holds about the client: status, next deadline, latest figures, tax due, review points. Each part comes from its own product, and is null when you can’t use that product or your credential has no scope for it; unavailable names those. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (ClientOverview).
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
todayrequired | string (date) | example "2026-03-31" |
createdAtrequired | string (date-time) | |
recordrequired | object (ClientRecord) | One client’s central record: what the firm holds, and what each product holds about them. A product’s part is null when this person or credential can’t use it. |
record.clientIdrequired | string (uuid) | |
record.namerequired | string | |
record.entityTyperequired | string (EntityType) | One of: |
record.companyNumberrequired | stringnullable | |
record.yearEndDayrequired | integernullable | 1 to 31 |
record.yearEndMonthrequired | integernullable | 1 to 12 |
record.statusrequired | string (ClientStatus) | One of: |
record.servicesrequired | array of ClientService | One of: |
record.utrrequired | stringnullable | Unique Taxpayer Reference, ten digits. |
record.vatNumberrequired | stringnullable | example "GB123456789" |
record.payeReferencerequired | stringnullable | Employer PAYE reference. example "123/AB456" |
record.registeredAddressrequired | stringnullable | |
record.principalActivity | stringnullable | Accounts and Corporation Tax default from this. |
record.signatoryName | stringnullable | Who usually signs the company’s accounts and returns. Accounts and Corporation Tax default from this. |
record.responsiblePartnerIdrequired | string (uuid)nullable | Set on the record; null when not set. |
record.clientManagerIdrequired | string (uuid)nullable | Set on the record; null when not set. |
record.responsiblePartnerrequired | object (ClientRecordPerson)nullable | Who to show: the record’s, else the latest engagement’s. |
record.responsiblePartner.idrequired | string (uuid) | |
record.responsiblePartner.namerequired | string | |
record.responsiblePartner.sourcerequired | string (ClientRecordPersonSource) | client: set on the record. latest_engagement: not set, so taken from the latest engagement’s team. One of: |
record.clientManagerrequired | object (ClientRecordPerson)nullable | Who to show: the record’s, else the latest engagement’s. |
record.clientManager.idrequired | string (uuid) | |
record.clientManager.namerequired | string | |
record.clientManager.sourcerequired | string (ClientRecordPersonSource) | client: set on the record. latest_engagement: not set, so taken from the latest engagement’s team. One of: |
record.contactsrequired | array of ClientContact | Primary first, then by name. |
record.contacts[].idrequired | string (uuid) | |
record.contacts[].namerequired | string | example "Jo Hartley" |
record.contacts[].rolerequired | stringnullable | example "Director" |
record.contacts[].emailrequired | stringnullable | |
record.contacts[].phonerequired | stringnullable | |
record.contacts[].isPrimaryrequired | boolean | The person to contact first. At most one per client. |
record.contacts[].appointedOn | string (date)nullable | For a director: appointed during the year. Blank means throughout. example "2026-03-31" |
record.contacts[].resignedOn | string (date)nullable | For a director: resigned during the year. example "2026-03-31" |
record.notesrequired | string | The client’s permanent notes. |
record.workrequired | object (ClientRecordWork)nullable | From Working Papers. |
record.work.currentrequired | object (ClientRecordEngagement)nullable | The latest year end. |
record.work.current.idrequired | string (uuid) | |
record.work.current.periodEndrequired | string (date) | example "2026-03-31" |
record.work.current.dueDaterequired | string (date) | example "2026-03-31" |
record.work.current.statusrequired | string | example "in_progress" |
record.work.current.stageNamerequired | string | |
record.work.yearEndsrequired | integer | |
record.work.openrequired | integer | Engagements not yet complete. |
record.work.nextDueDaterequired | string (date)nullable | The earliest filing deadline among engagements not yet complete. example "2026-03-31" |
record.meetingsrequired | object (ClientRecordMeetings)nullable | From Meetings. |
record.meetings.totalrequired | integer | |
record.meetings.openNextStepsrequired | integer | Next steps not yet sorted, across this client’s meetings. |
record.meetings.latestrequired | object (ClientRecordMeeting)nullable | |
record.meetings.latest.idrequired | string (uuid) | |
record.meetings.latest.titlerequired | string | |
record.meetings.latest.joinAtrequired | string (date-time) | |
record.meetings.latest.statusrequired | string | |
record.booksrequired | object (ClientRecordBooks) | Where the client’s books are, from its connection and its Tolvi Books link. |
record.books.connectionLabelrequired | stringnullable | The connected software, if any. example "Xero" |
record.books.connectionStatusrequired | stringnullable | The connection’s state: active, expired, revoked or error. |
record.books.booksLinkedrequired | boolean | The client is linked to a business in Tolvi Books. |
record.books.booksLiverequired | boolean | The link is live, so the firm can read those books. |
record.selfAssessment | object (ClientRecordProductWork)nullable | From Self Assessment. |
record.selfAssessment.totalrequired | integer | |
record.selfAssessment.openrequired | integer | Not yet filed, or for accounts not yet approved. |
record.selfAssessment.nextDueDaterequired | string (date)nullable | The earliest filing deadline among those still open. example "2026-03-31" |
record.selfAssessment.latestrequired | object (ClientRecordProductPeriod)nullable | The latest return or set of accounts. |
record.selfAssessment.latest.idrequired | string (uuid) | |
record.selfAssessment.latest.periodLabelrequired | string | example "2025/26" |
record.selfAssessment.latest.periodEndrequired | string (date) | example "2026-03-31" |
record.selfAssessment.latest.statusrequired | string | The product’s own status. |
record.selfAssessment.latest.stageLabelrequired | string | example "In review" |
record.selfAssessment.latest.dueDaterequired | string (date) | example "2026-03-31" |
record.accounts | object (ClientRecordProductWork)nullable | From Accounts. |
record.accounts.totalrequired | integer | |
record.accounts.openrequired | integer | Not yet filed, or for accounts not yet approved. |
record.accounts.nextDueDaterequired | string (date)nullable | The earliest filing deadline among those still open. example "2026-03-31" |
record.accounts.latestrequired | object (ClientRecordProductPeriod)nullable | The latest return or set of accounts. |
record.accounts.latest.idrequired | string (uuid) | |
record.accounts.latest.periodLabelrequired | string | example "2025/26" |
record.accounts.latest.periodEndrequired | string (date) | example "2026-03-31" |
record.accounts.latest.statusrequired | string | The product’s own status. |
record.accounts.latest.stageLabelrequired | string | example "In review" |
record.accounts.latest.dueDaterequired | string (date) | example "2026-03-31" |
record.corporationTax | object (ClientRecordProductWork)nullable | From Corporation Tax. |
record.corporationTax.totalrequired | integer | |
record.corporationTax.openrequired | integer | Not yet filed, or for accounts not yet approved. |
record.corporationTax.nextDueDaterequired | string (date)nullable | The earliest filing deadline among those still open. example "2026-03-31" |
record.corporationTax.latestrequired | object (ClientRecordProductPeriod)nullable | The latest return or set of accounts. |
record.corporationTax.latest.idrequired | string (uuid) | |
record.corporationTax.latest.periodLabelrequired | string | example "2025/26" |
record.corporationTax.latest.periodEndrequired | string (date) | example "2026-03-31" |
record.corporationTax.latest.statusrequired | string | The product’s own status. |
record.corporationTax.latest.stageLabelrequired | string | example "In review" |
record.corporationTax.latest.dueDaterequired | string (date) | example "2026-03-31" |
deadlinesrequired | array of ClientOverviewDeadline | Open work’s next deadlines across the products you can use, soonest first. |
deadlines[].productrequired | string | |
deadlines[].itemIdrequired | string (uuid) | |
deadlines[].kindrequired | string | |
deadlines[].labelrequired | string | |
deadlines[].periodLabelrequired | string | |
deadlines[].dueDaterequired | string (date) | example "2026-03-31" |
deadlines[].daysLeftrequired | integer | |
unavailablerequired | array of ClientOverviewUnavailable | Products you can’t use, so their parts are null. |
unavailable[].keyrequired | string | |
unavailable[].labelrequired | string | |
workingPapersrequired | object (ClientOverviewWorkingPapers)nullable | |
workingPapers.totalrequired | integer | |
workingPapers.openrequired | integer | |
workingPapers.nextDueDaterequired | string (date)nullable | example "2026-03-31" |
workingPapers.latestrequired | object (ClientOverviewLatest)nullable | |
workingPapers.latest.idrequired | string (uuid) | |
workingPapers.latest.periodLabelrequired | string | |
workingPapers.latest.periodEndrequired | string (date) | example "2026-03-31" |
workingPapers.latest.statusrequired | string | |
workingPapers.latest.stageLabelrequired | string | |
workingPapers.latest.dueDaterequired | string (date) | example "2026-03-31" |
workingPapers.openReviewPointsrequired | integer | |
workingPapers.periodsrequired | array of ClientOverviewPeriod | The latest six, newest first. |
workingPapers.periods[].idrequired | string (uuid) | |
workingPapers.periods[].labelrequired | string | |
workingPapers.periods[].periodEndrequired | string (date) | example "2026-03-31" |
workingPapers.periods[].statusrequired | string | |
workingPapers.periods[].stageLabelrequired | string | |
workingPapers.periods[].dueDaterequired | string (date) | example "2026-03-31" |
workingPapers.periods[].daysLeftrequired | integer | |
workingPapers.periods[].openReviewPointsrequired | integer | |
workingPapers.periods[].ownerNamerequired | stringnullable | |
workingPapers.softwarerequired | stringnullable | |
workingPapers.syncStaterequired | stringnullable | |
workingPapers.lastSyncedAtrequired | string (date-time)nullable | |
workingPapers.filedOnrequired | string (date)nullable | example "2026-03-31" |
workingPapers.openPointsrequired | integer | |
accountsrequired | object (ClientOverviewAccounts)nullable | |
accounts.totalrequired | integer | |
accounts.openrequired | integer | |
accounts.nextDueDaterequired | string (date)nullable | example "2026-03-31" |
accounts.latestrequired | object (ClientOverviewLatest)nullable | |
accounts.latest.idrequired | string (uuid) | |
accounts.latest.periodLabelrequired | string | |
accounts.latest.periodEndrequired | string (date) | example "2026-03-31" |
accounts.latest.statusrequired | string | |
accounts.latest.stageLabelrequired | string | |
accounts.latest.dueDaterequired | string (date) | example "2026-03-31" |
accounts.openReviewPointsrequired | integer | |
accounts.periodsrequired | array of ClientOverviewPeriod | The latest six, newest first. |
accounts.periods[].idrequired | string (uuid) | |
accounts.periods[].labelrequired | string | |
accounts.periods[].periodEndrequired | string (date) | example "2026-03-31" |
accounts.periods[].statusrequired | string | |
accounts.periods[].stageLabelrequired | string | |
accounts.periods[].dueDaterequired | string (date) | example "2026-03-31" |
accounts.periods[].daysLeftrequired | integer | |
accounts.periods[].openReviewPointsrequired | integer | |
accounts.periods[].ownerNamerequired | stringnullable | |
accounts.frameworkrequired | stringnullable | |
accounts.approvedOnrequired | string (date)nullable | example "2026-03-31" |
accounts.signatoryNamerequired | stringnullable | |
accounts.figuresrequired | object (ClientOverviewAccountsFigures)nullable | |
accounts.figures.turnoverPencerequired | integernullable | Pence. |
accounts.figures.profitPencerequired | integernullable | Pence. Negative for a loss. |
accounts.figures.netAssetsPencerequired | integernullable | Pence. |
accounts.figures.nextSteprequired | stringnullable | |
corporationTaxrequired | object (ClientOverviewCorporationTax)nullable | |
corporationTax.totalrequired | integer | |
corporationTax.openrequired | integer | |
corporationTax.nextDueDaterequired | string (date)nullable | example "2026-03-31" |
corporationTax.latestrequired | object (ClientOverviewLatest)nullable | |
corporationTax.latest.idrequired | string (uuid) | |
corporationTax.latest.periodLabelrequired | string | |
corporationTax.latest.periodEndrequired | string (date) | example "2026-03-31" |
corporationTax.latest.statusrequired | string | |
corporationTax.latest.stageLabelrequired | string | |
corporationTax.latest.dueDaterequired | string (date) | example "2026-03-31" |
corporationTax.openReviewPointsrequired | integer | |
corporationTax.periodsrequired | array of ClientOverviewPeriod | The latest six, newest first. |
corporationTax.periods[].idrequired | string (uuid) | |
corporationTax.periods[].labelrequired | string | |
corporationTax.periods[].periodEndrequired | string (date) | example "2026-03-31" |
corporationTax.periods[].statusrequired | string | |
corporationTax.periods[].stageLabelrequired | string | |
corporationTax.periods[].dueDaterequired | string (date) | example "2026-03-31" |
corporationTax.periods[].daysLeftrequired | integer | |
corporationTax.periods[].openReviewPointsrequired | integer | |
corporationTax.periods[].ownerNamerequired | stringnullable | |
corporationTax.taxDuePencerequired | integernullable | On the latest return, pence. Negative when overpaid. |
corporationTax.paymentDuerequired | string (date)nullable | example "2026-03-31" |
corporationTax.filedElsewhereOnrequired | string (date)nullable | The latest date a person recorded a return as filed outside Tolvi. Not HMRC’s word. example "2026-03-31" |
selfAssessmentrequired | object (ClientOverviewSelfAssessment)nullable | |
selfAssessment.totalrequired | integer | |
selfAssessment.openrequired | integer | |
selfAssessment.nextDueDaterequired | string (date)nullable | example "2026-03-31" |
selfAssessment.latestrequired | object (ClientOverviewLatest)nullable | |
selfAssessment.latest.idrequired | string (uuid) | |
selfAssessment.latest.periodLabelrequired | string | |
selfAssessment.latest.periodEndrequired | string (date) | example "2026-03-31" |
selfAssessment.latest.statusrequired | string | |
selfAssessment.latest.stageLabelrequired | string | |
selfAssessment.latest.dueDaterequired | string (date) | example "2026-03-31" |
selfAssessment.openReviewPointsrequired | integer | |
selfAssessment.periodsrequired | array of ClientOverviewPeriod | The latest six, newest first. |
selfAssessment.periods[].idrequired | string (uuid) | |
selfAssessment.periods[].labelrequired | string | |
selfAssessment.periods[].periodEndrequired | string (date) | example "2026-03-31" |
selfAssessment.periods[].statusrequired | string | |
selfAssessment.periods[].stageLabelrequired | string | |
selfAssessment.periods[].dueDaterequired | string (date) | example "2026-03-31" |
selfAssessment.periods[].daysLeftrequired | integer | |
selfAssessment.periods[].openReviewPointsrequired | integer | |
selfAssessment.periods[].ownerNamerequired | stringnullable | |
selfAssessment.taxDuePencerequired | integernullable | On the latest return, pence. Negative when overpaid. |
selfAssessment.returnTyperequired | stringnullable | |
vatrequired | object (ClientOverviewVat)nullable | |
vat.totalrequired | integer | |
vat.vatNumberrequired | stringnullable | On the record. |
vat.latestrequired | object (ClientOverviewVatLatest)nullable | |
vat.latest.idrequired | string (uuid) | |
vat.latest.periodKeyrequired | string | |
vat.latest.periodStartrequired | string (date) | example "2026-03-31" |
vat.latest.periodEndrequired | string (date) | example "2026-03-31" |
vat.latest.statusrequired | string | |
vat.latest.netDuePencerequired | integernullable | Box 5, pence. Negative when reclaimed. |
vat.latest.vrnrequired | string | The number this return was prepared under. |
booksrequired | object (ClientRecordBooks)nullable | Where the client’s books are, from its connection and its Tolvi Books link. |
books.connectionLabelrequired | stringnullable | The connected software, if any. example "Xero" |
books.connectionStatusrequired | stringnullable | The connection’s state: active, expired, revoked or error. |
books.booksLinkedrequired | boolean | The client is linked to a business in Tolvi Books. |
books.booksLiverequired | boolean | The link is live, so the firm can read those books. |
meetingsrequired | object (ClientRecordMeetings)nullable | From Meetings. |
meetings.totalrequired | integer | |
meetings.openNextStepsrequired | integer | Next steps not yet sorted, across this client’s meetings. |
meetings.latestrequired | object (ClientRecordMeeting)nullable | |
meetings.latest.idrequired | string (uuid) | |
meetings.latest.titlerequired | string | |
meetings.latest.joinAtrequired | string (date-time) | |
meetings.latest.statusrequired | string |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get one year end across the products
GET/api/v1/clients/{clientId}/period-chain
- Scopes
clients:read
Books, year-end file, accounts, CT return and filing for one year end, each with its status and the id to open. Only products you can use have a step, and only those the client’s type can have. Filing from Tolvi is marked as coming; a date a person recorded is shown as recorded. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | |
periodEnd | query | string (date) | The year end. Defaults to the latest with work. |
Responses
200 OK, application/json
Body: object (PeriodChain).
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
periodEndrequired | string (date)nullable | The year end shown. Null when the client has no work yet. example "2026-03-31" |
periodsrequired | array of string | Year ends with work, newest first, the latest six. |
stepsrequired | array of PeriodChainStep | In order. Only products you can use, and only those the client’s type can have. |
steps[].keyrequired | string (PeriodChainStepKey) | One of: |
steps[].labelrequired | string | |
steps[].itemIdrequired | string (uuid)nullable | The file, set or return for this year end. Null for books and filing, and when none has been started. |
steps[].stagerequired | stringnullable | not_started, preparing, returned, in_review, ready_to_file, filing or complete. Null when nothing has been started. |
steps[].statusLabelrequired | string | The status words the product itself shows. |
steps[].dueDaterequired | string (date)nullable | When the work is due or, on filing, the date a person recorded it as filed outside Tolvi. example "2026-03-31" |
steps[].openReviewPointsrequired | integer | |
steps[].comingrequired | boolean | Not open in Tolvi yet. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get the client’s central record
GET/api/v1/clients/{clientId}/record
- Scopes
clients:read
Details, identifiers, status, services, people and contacts, with what Working Papers, Meetings and the books hold about the client. A product’s part is null when you can’t use it or the credential has no scope for it. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (ClientRecord).
One client’s central record: what the firm holds, and what each product holds about them. A product’s part is null when this person or credential can’t use it.
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
namerequired | string | |
entityTyperequired | string (EntityType) | One of: |
companyNumberrequired | stringnullable | |
yearEndDayrequired | integernullable | 1 to 31 |
yearEndMonthrequired | integernullable | 1 to 12 |
statusrequired | string (ClientStatus) | One of: |
servicesrequired | array of ClientService | One of: |
utrrequired | stringnullable | Unique Taxpayer Reference, ten digits. |
vatNumberrequired | stringnullable | example "GB123456789" |
payeReferencerequired | stringnullable | Employer PAYE reference. example "123/AB456" |
registeredAddressrequired | stringnullable | |
principalActivity | stringnullable | Accounts and Corporation Tax default from this. |
signatoryName | stringnullable | Who usually signs the company’s accounts and returns. Accounts and Corporation Tax default from this. |
responsiblePartnerIdrequired | string (uuid)nullable | Set on the record; null when not set. |
clientManagerIdrequired | string (uuid)nullable | Set on the record; null when not set. |
responsiblePartnerrequired | object (ClientRecordPerson)nullable | Who to show: the record’s, else the latest engagement’s. |
responsiblePartner.idrequired | string (uuid) | |
responsiblePartner.namerequired | string | |
responsiblePartner.sourcerequired | string (ClientRecordPersonSource) | client: set on the record. latest_engagement: not set, so taken from the latest engagement’s team. One of: |
clientManagerrequired | object (ClientRecordPerson)nullable | Who to show: the record’s, else the latest engagement’s. |
clientManager.idrequired | string (uuid) | |
clientManager.namerequired | string | |
clientManager.sourcerequired | string (ClientRecordPersonSource) | client: set on the record. latest_engagement: not set, so taken from the latest engagement’s team. One of: |
contactsrequired | array of ClientContact | Primary first, then by name. |
contacts[].idrequired | string (uuid) | |
contacts[].namerequired | string | example "Jo Hartley" |
contacts[].rolerequired | stringnullable | example "Director" |
contacts[].emailrequired | stringnullable | |
contacts[].phonerequired | stringnullable | |
contacts[].isPrimaryrequired | boolean | The person to contact first. At most one per client. |
contacts[].appointedOn | string (date)nullable | For a director: appointed during the year. Blank means throughout. example "2026-03-31" |
contacts[].resignedOn | string (date)nullable | For a director: resigned during the year. example "2026-03-31" |
notesrequired | string | The client’s permanent notes. |
workrequired | object (ClientRecordWork)nullable | From Working Papers. |
work.currentrequired | object (ClientRecordEngagement)nullable | The latest year end. |
work.current.idrequired | string (uuid) | |
work.current.periodEndrequired | string (date) | example "2026-03-31" |
work.current.dueDaterequired | string (date) | example "2026-03-31" |
work.current.statusrequired | string | example "in_progress" |
work.current.stageNamerequired | string | |
work.yearEndsrequired | integer | |
work.openrequired | integer | Engagements not yet complete. |
work.nextDueDaterequired | string (date)nullable | The earliest filing deadline among engagements not yet complete. example "2026-03-31" |
meetingsrequired | object (ClientRecordMeetings)nullable | From Meetings. |
meetings.totalrequired | integer | |
meetings.openNextStepsrequired | integer | Next steps not yet sorted, across this client’s meetings. |
meetings.latestrequired | object (ClientRecordMeeting)nullable | |
meetings.latest.idrequired | string (uuid) | |
meetings.latest.titlerequired | string | |
meetings.latest.joinAtrequired | string (date-time) | |
meetings.latest.statusrequired | string | |
booksrequired | object (ClientRecordBooks) | Where the client’s books are, from its connection and its Tolvi Books link. |
books.connectionLabelrequired | stringnullable | The connected software, if any. example "Xero" |
books.connectionStatusrequired | stringnullable | The connection’s state: active, expired, revoked or error. |
books.booksLinkedrequired | boolean | The client is linked to a business in Tolvi Books. |
books.booksLiverequired | boolean | The link is live, so the firm can read those books. |
selfAssessment | object (ClientRecordProductWork)nullable | From Self Assessment. |
selfAssessment.totalrequired | integer | |
selfAssessment.openrequired | integer | Not yet filed, or for accounts not yet approved. |
selfAssessment.nextDueDaterequired | string (date)nullable | The earliest filing deadline among those still open. example "2026-03-31" |
selfAssessment.latestrequired | object (ClientRecordProductPeriod)nullable | The latest return or set of accounts. |
selfAssessment.latest.idrequired | string (uuid) | |
selfAssessment.latest.periodLabelrequired | string | example "2025/26" |
selfAssessment.latest.periodEndrequired | string (date) | example "2026-03-31" |
selfAssessment.latest.statusrequired | string | The product’s own status. |
selfAssessment.latest.stageLabelrequired | string | example "In review" |
selfAssessment.latest.dueDaterequired | string (date) | example "2026-03-31" |
accounts | object (ClientRecordProductWork)nullable | From Accounts. |
accounts.totalrequired | integer | |
accounts.openrequired | integer | Not yet filed, or for accounts not yet approved. |
accounts.nextDueDaterequired | string (date)nullable | The earliest filing deadline among those still open. example "2026-03-31" |
accounts.latestrequired | object (ClientRecordProductPeriod)nullable | The latest return or set of accounts. |
accounts.latest.idrequired | string (uuid) | |
accounts.latest.periodLabelrequired | string | example "2025/26" |
accounts.latest.periodEndrequired | string (date) | example "2026-03-31" |
accounts.latest.statusrequired | string | The product’s own status. |
accounts.latest.stageLabelrequired | string | example "In review" |
accounts.latest.dueDaterequired | string (date) | example "2026-03-31" |
corporationTax | object (ClientRecordProductWork)nullable | From Corporation Tax. |
corporationTax.totalrequired | integer | |
corporationTax.openrequired | integer | Not yet filed, or for accounts not yet approved. |
corporationTax.nextDueDaterequired | string (date)nullable | The earliest filing deadline among those still open. example "2026-03-31" |
corporationTax.latestrequired | object (ClientRecordProductPeriod)nullable | The latest return or set of accounts. |
corporationTax.latest.idrequired | string (uuid) | |
corporationTax.latest.periodLabelrequired | string | example "2025/26" |
corporationTax.latest.periodEndrequired | string (date) | example "2026-03-31" |
corporationTax.latest.statusrequired | string | The product’s own status. |
corporationTax.latest.stageLabelrequired | string | example "In review" |
corporationTax.latest.dueDaterequired | string (date) | example "2026-03-31" |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Change the client’s central record
PATCH/api/v1/clients/{clientId}/record
- Scopes
clients:write- Role
- Preparer or above
Preparers and above. Refused when an identifier isn’t in the right form, or the responsible partner or client manager doesn’t hold that role in this firm. Doesn’t change who is assigned to any engagement.
Needs the Preparer role or above. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Request body
Required. application/json: object (UpdateClientRecordRequest).
Send only what changes; null or blank clears a field.
| Field | Type | Description |
|---|---|---|
name | string | The client’s name. Work in progress reads it from here; an approved return or accounts keep the name they were approved under. up to 200 characters |
entityType | string (EntityType) | What the client is. Decides what new work can start; work already started keeps what it started with. One of: |
companyNumber | stringnullable | Companies House number. |
yearEndDay | integernullable | Year end day, sent with yearEndMonth. 1 to 31 |
yearEndMonth | integernullable | Year end month, sent with yearEndDay. 1 to 12 |
status | string (ClientStatus) | One of: |
services | array of ClientService | One of: |
utr | stringnullable | |
vatNumber | stringnullable | |
payeReference | stringnullable | |
registeredAddress | stringnullable | up to 500 characters |
principalActivity | stringnullable | up to 1000 characters |
signatoryName | stringnullable | Who usually signs the company’s accounts and returns. up to 200 characters |
responsiblePartnerId | string (uuid)nullable | Must be a partner in the firm. |
clientManagerId | string (uuid)nullable | Must be a manager or partner in the firm. |
Responses
200 OK, application/json
Body: object (ClientRecord).
One client’s central record: what the firm holds, and what each product holds about them. A product’s part is null when this person or credential can’t use it.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get the company facts on the record
GET/api/v1/clients/{clientId}/company-facts
- Scopes
clients:read
Registered office, principal activity, signatory and directors, as Accounts and Corporation Tax read them. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (CompanyFacts).
What the client’s record says about the company. Accounts and Corporation Tax start from this; a person chooses to save a change back.
| Field | Type | Description |
|---|---|---|
namerequired | stringnullable | The client’s name on the record. |
companyNumberrequired | stringnullable | Companies House number on the record. |
registeredOfficerequired | stringnullable | |
principalActivityrequired | stringnullable | |
signatoryNamerequired | stringnullable | The record’s, or the only serving director. |
directorsrequired | array of RecordDirector | Contacts whose role says director. |
directors[].namerequired | string | |
directors[].appointedOn | string (date) | example "2026-03-31" |
directors[].resignedOn | string (date) | example "2026-03-31" |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Save directors to the record
PUT/api/v1/clients/{clientId}/directors
- Scopes
clients:write- Role
- Preparer or above
Preparers and above. Adds each person as a contact with the role Director, or updates their dates. Nobody is removed: take someone off in Contacts.
Needs the Preparer role or above. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Request body
Required. application/json: object (SaveDirectorsRequest).
Adds these people as contacts with the role Director, or updates their dates. Nobody is removed.
| Field | Type | Description |
|---|---|---|
directorsrequired | array of RecordDirector | |
directors[].namerequired | string | |
directors[].appointedOn | string (date) | example "2026-03-31" |
directors[].resignedOn | string (date) | example "2026-03-31" |
Responses
200 OK, application/json
Body: object (CompanyFacts).
What the client’s record says about the company. Accounts and Corporation Tax start from this; a person chooses to save a change back.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Add a contact
POST/api/v1/clients/{clientId}/contacts
- Scopes
clients:write- Role
- Preparer or above
- Retries
- Send an
Idempotency-Keyto make retries safe.
Preparers and above. The client’s first contact becomes its primary contact.
Needs the Preparer role or above. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | |
Idempotency-Key | header | string | A unique key (1-255 visible characters) to make retries safe. Replayed for 24 hours. 1 to 255 characters |
Request body
Required. application/json: object (CreateClientContactRequest).
| Field | Type | Description |
|---|---|---|
namerequired | string | 1 to 200 characters |
role | stringnullable | up to 100 characters |
email | string (email)nullable | |
phone | stringnullable | up to 40 characters |
isPrimary | boolean | The client’s first contact is primary anyway. Setting this moves it from whoever had it. |
appointedOn | string (date)nullable | example "2026-03-31" |
resignedOn | string (date)nullable | example "2026-03-31" |
Responses
201 Created, application/json
Body: object (ClientContact).
A person at a client.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
namerequired | string | example "Jo Hartley" |
rolerequired | stringnullable | example "Director" |
emailrequired | stringnullable | |
phonerequired | stringnullable | |
isPrimaryrequired | boolean | The person to contact first. At most one per client. |
appointedOn | string (date)nullable | For a director: appointed during the year. Blank means throughout. example "2026-03-31" |
resignedOn | string (date)nullable | For a director: resigned during the year. example "2026-03-31" |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 409 Conflict, 422 Unprocessable content, 429 Too many requests, as problem details (application/problem+json).
Change a contact
PATCH/api/v1/clients/{clientId}/contacts/{contactId}
- Scopes
clients:write- Role
- Preparer or above
Preparers and above.
Needs the Preparer role or above. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | |
contactIdrequired | path | string (uuid) |
Request body
Required. application/json: object (UpdateClientContactRequest).
Send only what changes.
| Field | Type | Description |
|---|---|---|
name | string | 1 to 200 characters |
role | stringnullable | up to 100 characters |
email | string (email)nullable | |
phone | stringnullable | up to 40 characters |
isPrimary | boolean | Setting this moves it from whoever had it. |
appointedOn | string (date)nullable | example "2026-03-31" |
resignedOn | string (date)nullable | example "2026-03-31" |
Responses
200 OK, application/json
Body: object (ClientContact).
A person at a client.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Remove a contact
DELETE/api/v1/clients/{clientId}/contacts/{contactId}
- Scopes
clients:write- Role
- Preparer or above
Preparers and above. If it was the primary contact, the next by name takes over.
Needs the Preparer role or above. Part of the hub product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | |
contactIdrequired | path | string (uuid) |
Responses
204 No content
Removed.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).