Integrations
21 operations in the Tolvi API, version 1. Paths are relative to https://api.tolvi.co.uk. Every amount is integer pence.
List bookkeeping providers
GET/api/v1/integrations/providers
- Scopes
clients:read
Which providers this Tolvi deployment is set up for (developer app credentials present), and this firm’s connections to each by status.
Responses
200 OK, application/json
Body: object (IntegrationProviders).
| Field | Type | Description |
|---|---|---|
providersrequired | array of IntegrationProviderInfo | |
providers[].idrequired | string (IntegrationProvider) | One of: |
providers[].labelrequired | string | example "Xero" |
providers[].configuredrequired | boolean | Set up for this Tolvi deployment (developer app credentials present). Only configured providers can be connected. |
providers[].connectionsrequired | object (ConnectionCounts) | This firm’s client connections to the provider, by status. |
providers[].connections.activerequired | integer | at least 0 |
providers[].connections.expiredrequired | integer | Refresh token lapsed or access removed: needs reconnecting. at least 0 |
providers[].connections.revokedrequired | integer | at least 0 |
providers[].connections.errorrequired | integer | at least 0 |
providers[].connections.needsOrganisationrequired | integer | Connected, but the organisation has not been chosen yet. at least 0 |
fakerequired | boolean | Development only: the fixture-driven fake provider stands in for every provider. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Finish connecting a client’s books
POST/api/v1/integrations/callback
- Scopes
integrations:manage- Access
- A signed-in Tolvi session only, never an API token.
Called by the web app’s /integrations/callback/{provider} page with the code and state from the provider’s redirect, as the signed-in user who started the connect. The state is single-use and expires after 10 minutes. With one organisation it is bound at once; with several, choose one with PUT /clients/{clientId}/connection/organisation. A practice connect (POST /integrations/practice/authorize) is refused with 409 and its state left unused: finish it with POST /integrations/practice/callback.
Request body
Required. application/json: object (IntegrationCallbackRequest).
| Field | Type | Description |
|---|---|---|
providerrequired | string (IntegrationProvider) | One of: |
coderequired | string | The 1 to 4096 characters |
staterequired | string | The 1 to 512 characters |
params | object | Any other query parameters from the redirect (QuickBooks sends realmId). |
Responses
200 OK, application/json
Body: object (IntegrationCallbackResult).
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | The client connected. |
grantIdrequired | string (uuid)nullable | Always null. Kept for compatibility: a practice connect finishes with POST /integrations/practice/callback, which returns the grantId. |
outcomerequired | string (IntegrationCallbackOutcome) | One of: |
connectionrequired | object (ClientConnection) | |
connection.clientIdrequired | string (uuid) | |
connection.connectedrequired | boolean | |
connection.providerrequired | string (IntegrationProvider)nullable | One of: |
connection.providerLabelrequired | stringnullable | example "Xero" |
connection.statusrequired | string (ConnectionStatus)nullable | One of: |
connection.orgIdrequired | stringnullable | |
connection.orgNamerequired | stringnullable | |
connection.needsOrganisationrequired | boolean | Several organisations were authorised: choose one with PUT …/connection/organisation. |
connection.organisationsrequired | array of ConnectionOrganisation | The organisations to choose from (only while needsOrganisation). |
connection.organisations[].idrequired | string | The provider’s organisation (tenant, realm, business or company) id. |
connection.organisations[].namerequired | string | |
connection.viaPracticerequired | boolean | Connected by importing clients from the practice’s Xero: the tokens are the practice authorisation’s, shared with the other clients imported with it. |
connection.lastErrorrequired | stringnullable | The last failure, in words. Never contains a token. |
connection.lastSyncedAtrequired | string (date-time)nullable | |
connection.connectedAtrequired | string (date-time)nullable | |
connection.connectedByrequired | string (uuid)nullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Finish importing clients from Xero
POST/api/v1/integrations/practice/callback
- Scopes
integrations:manageandclients:write- Access
- A signed-in Tolvi session only, never an API token.
Called by the web app’s /integrations/callback/{provider} page with the code and state from Xero’s redirect, as the signed-in user who started the import (POST /integrations/practice/authorize). The state is single-use and expires after 10 minutes. Stores one authorisation for every organisation the adviser ticked and returns its grantId; nothing is imported until POST /integrations/practice/grants/{grantId}/import. A client’s connect is refused with 409 and its state left unused: finish it with POST /integrations/callback.
Request body
Required. application/json: object (PracticeCallbackRequest).
| Field | Type | Description |
|---|---|---|
providerrequired | string (PracticeProvider) | Only Xero offers the organisation details the import needs. One of: |
coderequired | string | The 1 to 4096 characters |
staterequired | string | The 1 to 512 characters |
params | object | Any other query parameters from the redirect. |
Responses
200 OK, application/json
Body: object (PracticeCallbackResult).
| Field | Type | Description |
|---|---|---|
grantIdrequired | string (uuid) | The authorisation to import clients from (GET /integrations/practice/grants/{grantId}/organisations). |
outcomerequired | string (PracticeCallbackOutcome) | One of: |
organisationCountrequired | integer | Organisations the adviser authorised. at least 1 |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
List practice authorisations
GET/api/v1/integrations/practice/grants
- Scopes
integrations:manage
This firm’s Xero authorisations for importing clients, newest first. Tokens are never returned.
Responses
200 OK, application/json
Body: object (PracticeGrantList).
| Field | Type | Description |
|---|---|---|
rowsrequired | array of PracticeGrant | Newest first. |
rows[].idrequired | string (uuid) | |
rows[].providerrequired | string (IntegrationProvider) | One of: |
rows[].providerLabelrequired | string | example "Xero" |
rows[].statusrequired | string (ConnectionStatus) | One of: |
rows[].organisationCountrequired | integer | Organisations the adviser authorised. at least 0 |
rows[].clientsConnectedrequired | integer | Clients connected through this authorisation. at least 0 |
rows[].lastErrorrequired | stringnullable | |
rows[].connectedAtrequired | string (date-time) | |
rows[].connectedByrequired | string (uuid)nullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
List the organisations to import
GET/api/v1/integrations/practice/grants/{grantId}/organisations
- Scopes
integrations:manage
Each organisation the adviser authorised, as Xero describes it (name, legal form, Companies House and VAT numbers, financial year end), with the suggested entity type, the next year end, and whether it is already in Tolvi (matched by company number, then name) or already connected.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
grantIdrequired | path | string (uuid) | Practice authorisation id. |
Responses
200 OK, application/json
Body: object (PracticeOrganisationList).
| Field | Type | Description |
|---|---|---|
grantrequired | object (PracticeGrant) | |
grant.idrequired | string (uuid) | |
grant.providerrequired | string (IntegrationProvider) | One of: |
grant.providerLabelrequired | string | example "Xero" |
grant.statusrequired | string (ConnectionStatus) | One of: |
grant.organisationCountrequired | integer | Organisations the adviser authorised. at least 0 |
grant.clientsConnectedrequired | integer | Clients connected through this authorisation. at least 0 |
grant.lastErrorrequired | stringnullable | |
grant.connectedAtrequired | string (date-time) | |
grant.connectedByrequired | string (uuid)nullable | |
organisationsrequired | array of PracticeOrganisation | |
organisations[].orgIdrequired | string | The provider’s organisation (tenant) id. |
organisations[].namerequired | string | The client name to use (the legal name when Xero has one). |
organisations[].legalNamerequired | stringnullable | |
organisations[].organisationTyperequired | stringnullable | The provider’s own word for the legal form, e.g. COMPANY, PARTNERSHIP, SOLE_TRADER, CHARITY. |
organisations[].entityTyperequired | string (EntityType)nullable | Suggested Tolvi entity type; null when Tolvi doesn’t prepare this kind of entity (choose one to import it). One of: |
organisations[].entityTypeReasonrequired | string | |
organisations[].companyNumberrequired | stringnullable | Companies House number, normalised (companies and LLPs only). |
organisations[].vatNumberrequired | stringnullable | VAT number as held in Xero. |
organisations[].yearEndDayrequired | integernullable | 1 to 31 |
organisations[].yearEndMonthrequired | integernullable | 1 to 12 |
organisations[].nextPeriodEndrequired | string (date)nullable | The first year end on or after today (29 February becomes 28 February outside leap years). example "2026-03-31" |
organisations[].baseCurrencyrequired | stringnullable | |
organisations[].isDemoCompanyrequired | boolean | |
organisations[].warningsrequired | array of string | Reasons it isn’t ticked by default. |
organisations[].profileErrorrequired | stringnullable | Why the organisation’s details couldn’t be read (not importable until reconnected). |
organisations[].connectedClientrequired | object (PracticeClientRef)nullable | Already connected to this Tolvi client. |
organisations[].connectedClient.clientIdrequired | string (uuid) | |
organisations[].connectedClient.clientNamerequired | string | |
organisations[].matchrequired | object (PracticeClientMatch)nullable | Already in Tolvi: importing links to this client instead of creating one. |
organisations[].match.clientIdrequired | string (uuid) | |
organisations[].match.clientNamerequired | string | |
organisations[].match.matchedByrequired | string (PracticeMatchBasis) | One of: |
organisations[].match.connectedElsewhererequired | stringnullable | The client is already connected to other books (it is then left as it is). |
organisations[].suggestedrequired | boolean | Pre-tick it: new to Tolvi, a type Tolvi prepares and nothing to check. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Import clients from Xero
POST/api/v1/integrations/practice/grants/{grantId}/import
- Scopes
integrations:manageandclients:write- Retries
- Send an
Idempotency-Keyto make retries safe.
Creates a client for each chosen organisation, or links it to the client it matches (company number, then name; never a duplicate), sets the year end, and connects the client’s books through this authorisation so the trial balance can be pulled without connecting again. Organisations already connected, or matching a client connected to other books, are reported and left alone.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
grantIdrequired | path | string (uuid) | Practice authorisation id. |
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 (PracticeImportRequest).
| Field | Type | Description |
|---|---|---|
organisationsrequired | array of PracticeImportItem | 1 to 1000 items |
organisations[].orgIdrequired | string | 1 to 200 characters |
organisations[].entityType | string (EntityType) | For a new client; defaults to the suggestion. Ignored when linking. One of: |
organisations[].yearEndDay | integernullable | Year end day (with yearEndMonth); defaults to none. 1 to 31 |
organisations[].yearEndMonth | integernullable | 1 to 12 |
organisations[].clientId | string (uuid) | Link to this existing client instead of matching. |
organisations[].createNew | boolean | Create a new client even if one matches. |
Responses
200 OK, application/json
Body: object (PracticeImportResult).
| Field | Type | Description |
|---|---|---|
createdrequired | integer | at least 0 |
linkedrequired | integer | at least 0 |
alreadyConnectedrequired | integer | at least 0 |
skippedrequired | integer | at least 0 |
resultsrequired | array of PracticeImportOutcome | |
results[].orgIdrequired | string | |
results[].orgNamerequired | string | |
results[].outcomerequired | string (PracticeImportOutcomeKind) | One of: |
results[].clientIdrequired | string (uuid)nullable | |
results[].clientNamerequired | stringnullable | |
results[].reasonrequired | stringnullable | Why it was skipped. |
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).
Remove a practice authorisation
DELETE/api/v1/integrations/practice/grants/{grantId}
- Scopes
integrations:manage
Revokes it at Xero and disconnects every client connected through it (their open engagements go back to manual). Clients and imported trial balances are kept.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
grantIdrequired | path | string (uuid) | Practice authorisation id. |
Responses
204 No content
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get a client’s bookkeeping connection
GET/api/v1/clients/{clientId}/connection
- Scopes
clients:read
Status, organisation and when the books were last read. Tokens are never returned.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
200 OK, application/json
Body: object (ClientConnection).
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
connectedrequired | boolean | |
providerrequired | string (IntegrationProvider)nullable | One of: |
providerLabelrequired | stringnullable | example "Xero" |
statusrequired | string (ConnectionStatus)nullable | One of: |
orgIdrequired | stringnullable | |
orgNamerequired | stringnullable | |
needsOrganisationrequired | boolean | Several organisations were authorised: choose one with PUT …/connection/organisation. |
organisationsrequired | array of ConnectionOrganisation | The organisations to choose from (only while needsOrganisation). |
organisations[].idrequired | string | The provider’s organisation (tenant, realm, business or company) id. |
organisations[].namerequired | string | |
viaPracticerequired | boolean | Connected by importing clients from the practice’s Xero: the tokens are the practice authorisation’s, shared with the other clients imported with it. |
lastErrorrequired | stringnullable | The last failure, in words. Never contains a token. |
lastSyncedAtrequired | string (date-time)nullable | |
connectedAtrequired | string (date-time)nullable | |
connectedByrequired | string (uuid)nullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Disconnect a client’s books
DELETE/api/v1/clients/{clientId}/connection
- Scopes
integrations:manage
Revokes Tolvi’s access at the provider where it supports that (Xero, QuickBooks, Sage; for FreeAgent remove the app there), then forgets the connection. Imported trial balances are kept.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
204 No content
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Choose the client’s organisation
PUT/api/v1/clients/{clientId}/connection/organisation
- Scopes
integrations:manage- Access
- A signed-in Tolvi session only, never an API token.
One of the organisations the connection was authorised for.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Request body
Required. application/json: object (ChooseOrganisationRequest).
| Field | Type | Description |
|---|---|---|
orgIdrequired | string | 1 to 200 characters |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get a client’s chart of accounts
GET/api/v1/clients/{clientId}/chart-of-accounts
- Scopes
clients:read
Every account in the client’s books, with or without a balance (the trial balance lists only accounts with balances), as last read from their bookkeeping software or imported from a CSV, with the lead schedule line each would map to. Section C and journals offer these real nominal codes.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
200 OK, application/json
Body: object (ChartOfAccounts).
The client’s chart of accounts, read from their bookkeeping software (on connect, on every TB pull, and on refresh) or imported from a CSV.
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
sourcerequired | string (ChartOfAccountsSource)nullable | Null until a chart has been read or imported. One of: |
sourceLabelrequired | stringnullable | example "Xero" |
syncedAtrequired | string (date-time)nullable | When the chart was last read or imported. |
canRefreshrequired | boolean | The client’s books are connected (or linked to Tolvi Books), so POST …/chart-of-accounts/refresh can read the chart again. |
accountsrequired | array of ChartAccount | |
accounts[].coderequired | string | |
accounts[].namerequired | string | |
accounts[].typerequired | string (ChartAccountType)nullable | One of: |
accounts[].providerTyperequired | stringnullable | The software’s own type, e.g. Xero’s FIXED or DEPRECIATN, or the CSV’s Type column. |
accounts[].activerequired | boolean | False for archived or inactive accounts. |
accounts[].lineIdrequired | string (LeadLineId)nullable | The lead schedule line the mapping order suggests (client memory, firm rules, built-in). One of: |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Import a client’s chart of accounts from a CSV
PUT/api/v1/clients/{clientId}/chart-of-accounts
- Scopes
clients:write
For a client whose books are not connected: replaces the stored chart with the file’s accounts. The file needs Code and Name columns; Type and Status are read where present (Xero’s chart of accounts export works as it is). 422 with the reason when the file can’t be read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Request body
Required. application/json: object (ImportChartOfAccountsRequest).
| Field | Type | Description |
|---|---|---|
formatrequired | string (ChartOfAccountsFormat) | One of: |
contentrequired | string | The CSV text: Code and Name columns, with Type and Status where the file has them (Xero’s chart of accounts export works as it is). up to 2000000 characters |
Responses
200 OK, application/json
Body: object (ChartOfAccounts).
The client’s chart of accounts, read from their bookkeeping software (on connect, on every TB pull, and on refresh) or imported from a CSV.
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).
Read a client’s chart of accounts again
POST/api/v1/clients/{clientId}/chart-of-accounts/refresh
- Scopes
clients:write
Reads the chart from the client’s connected books and replaces the stored one. Tolvi also does this when the books are connected and on every trial balance pull. 409 when the books are not connected or the connection needs reconnecting.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
200 OK, application/json
Body: object (ChartOfAccounts).
The client’s chart of accounts, read from their bookkeeping software (on connect, on every TB pull, and on refresh) or imported from a CSV.
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 a client’s link to Tolvi Books
GET/api/v1/clients/{clientId}/books-link
- Scopes
clients:read
Which business’s Tolvi Books is this client’s, the practice link’s status and access, which source its engagements pull the trial balance from (or that someone must choose, when it also has an OAuth connection), and the books at a glance (read through the link).
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
200 OK, application/json
Body: object (ClientBooksLink).
Which business’s Tolvi Books is this client’s, through which of the firm’s practice links. The link is the business’s to grant and end; unlinking here only forgets which client it is.
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
linkedrequired | boolean | |
sourcerequired | string (BooksLinkSource) | Always tolvi_books: reached through a practice link, not OAuth. One of: |
sourceLabelrequired | string | example "Tolvi Books" |
businessIdrequired | string (uuid)nullable | The business’s tenant id (send it as x-business-id to work in its books). |
businessNamerequired | stringnullable | |
practiceLinkIdrequired | string (uuid)nullable | |
linkStatusrequired | string (PracticeLinkStatus)nullable | ended: the business (or the firm) ended the link; relink or unlink. One of: |
accessrequired | string (PracticeAccess)nullable | read_only: see the books, export, pull the TB. year_end: also post year-end adjustments. full_bookkeeping: also keep the books. One of: |
consentBasisrequired | string (LinkConsentBasis)nullable | practice_provisioned: the firm set the books up and looks after them until the owner joins. One of: |
linkedAtrequired | string (date-time)nullable | |
linkedByrequired | string (uuid)nullable | |
trialBalanceAvailablerequired | boolean | The trial balance can be pulled straight from the client’s Tolvi Books now (linked, and the link is live). |
connectionProviderrequired | string (IntegrationProvider)nullable | The client’s OAuth connection, when it also has one. One of: |
connectionLabelrequired | stringnullable | example "Xero" |
sourceChoicerequired | string (BooksSourcePick)nullable | When the client has both an OAuth connection and a Tolvi Books link: the one a person chose for its engagements (PUT …/books-link/source). Null until chosen, and with only one source. One of: |
needsSourceChoicerequired | boolean | The client has both sources and nobody has chosen: trial balance pulls ask until someone does. Tolvi never picks one itself. |
sourceInUserequired | string (BooksSource)nullable | The source the client’s engagements pull their trial balance from now. One of: |
healthrequired | object (BooksHealth)nullable | The books at a glance, read through the link; null when not linked or the link has ended. |
health.entriesrequired | integer | Ledger entries posted. at least 0 |
health.lastPostedAtrequired | string (date-time)nullable | |
health.lastEntryDaterequired | string (date)nullable | The latest date any entry is dated. example "2026-03-31" |
health.receiptsToReviewrequired | integer | Receipts read and waiting to be confirmed. at least 0 |
health.unexplainedBankLinesrequired | integernullable | Bank lines not yet explained. Null until bank feeds are available. at least 0 |
health.vatRegisteredrequired | boolean | |
health.vatSchemerequired | stringnullable | example "standard" |
health.nextVatDuerequired | string (date)nullable | The next VAT return due. Null until MTD VAT returns are available. 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).
Link a client to a business’s Tolvi Books
PUT/api/v1/clients/{clientId}/books-link
- Scopes
integrations:manage- Access
- A signed-in Tolvi session only, never an API token.
Through one of the firm’s active practice links (the business grants it). One client per business; relinking replaces the client’s earlier link.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Request body
Required. application/json: object (LinkClientBooks).
| Field | Type | Description |
|---|---|---|
practiceLinkIdrequired | string (uuid) | One of the firm’s active practice links (GET /clients/{clientId}/books-link/candidates). |
Responses
200 OK, application/json
Body: object (ClientBooksLink).
Which business’s Tolvi Books is this client’s, through which of the firm’s practice links. The link is the business’s to grant and end; unlinking here only forgets which client it is.
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).
Unlink a client from Tolvi Books
DELETE/api/v1/clients/{clientId}/books-link
- Scopes
integrations:manage- Access
- A signed-in Tolvi session only, never an API token.
Forgets which business’s books this client is. The practice link itself is unchanged: end it under Clients’ books.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
204 No content
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
List businesses’ books this client could be linked to
GET/api/v1/clients/{clientId}/books-link/candidates
- Scopes
clients:readandclient_books:read
Every business that has granted the firm an active link, with the client each is already linked to. Those named like this client and not yet linked are suggested.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Responses
200 OK, application/json
Body: object (BooksLinkCandidateList).
| Field | Type | Description |
|---|---|---|
rowsrequired | array of BooksLinkCandidate | |
rows[].practiceLinkIdrequired | string (uuid) | |
rows[].businessIdrequired | string (uuid) | |
rows[].businessNamerequired | stringnullable | |
rows[].accessrequired | string (PracticeAccess) | read_only: see the books, export, pull the TB. year_end: also post year-end adjustments. full_bookkeeping: also keep the books. One of: |
rows[].consentBasisrequired | string (LinkConsentBasis) | One of: |
rows[].linkedClientIdrequired | string (uuid)nullable | The client it is already linked to, if any. |
rows[].linkedClientNamerequired | stringnullable | |
rows[].suggestedrequired | boolean | Not linked yet and named like this client. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Choose which source a client’s engagements use
PUT/api/v1/clients/{clientId}/books-link/source
- Scopes
integrations:manage- Access
- A signed-in Tolvi session only, never an API token.
For a client with both an OAuth connection and a Tolvi Books link: whether its engagements pull the trial balance from its Tolvi Books (tolvi_books) or its OAuth connection (connection). Tolvi never chooses itself: until someone does, pulls are refused (409) with a request to choose. Stored on the client and can be changed later; open engagements follow, each shown as not yet read until its next pull. 409 when the client doesn’t have both, or the chosen one can’t be read.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
Request body
Required. application/json: object (ChooseBooksSource).
Which source a client with both an OAuth connection and a Tolvi Books link uses for its engagements.
| Field | Type | Description |
|---|---|---|
userequired | string (BooksSourcePick) | tolvi_books: the client’s Tolvi Books. connection: its OAuth connection (Xero, QuickBooks, Sage or FreeAgent). One of: |
Responses
200 OK, application/json
Body: object (ClientBooksLink).
Which business’s Tolvi Books is this client’s, through which of the firm’s practice links. The link is the business’s to grant and end; unlinking here only forgets which client it is.
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).
Invite a client’s business to Tolvi Books
POST/api/v1/clients/{clientId}/books-link/invitation
- Scopes
integrations:manageandclient_books:read- Access
- A signed-in Tolvi session only, never an API token.
- Retries
- Send an
Idempotency-Keyto make retries safe.
Sets Tolvi Books up from the client record (name, entity type, company number, year end) with the firm as its accountant under the firm’s engagement letter, invites the owner when an email is given, and links the client. Managers, partners and firm admins only.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) | Client id. |
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 (InviteClientToBooks).
Set Tolvi Books up for this client from its record, and link it.
| Field | Type | Description |
|---|---|---|
ownerEmail | string (email) | Invite the owner now. Without it the firm looks after the books until it invites someone. up to 254 characters |
billedBy | string (LinkBilledBy) | Who pays for Tolvi Books. Defaults to the practice. One of: |
Responses
201 Created, application/json
Body: object (ClientBooksLink).
Which business’s Tolvi Books is this client’s, through which of the firm’s practice links. The link is the business’s to grant and end; unlinking here only forgets which client it is.
The fields are as shown above.
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).