Books: sales
41 operations in the Tolvi API, version 1. Paths are relative to https://api.tolvi.co.uk. Every amount is integer pence.
Who owes the business money
GET/api/v1/books/sales/summary
- Scopes
books:read
What is owed and overdue as at today, by customer (most overdue first), with drafts and reminders waiting for the owner. Part of the books product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (SalesSummary).
Who owes the business money, as at today.
| Field | Type | Description |
|---|---|---|
asAtrequired | string (date) | example "2026-03-31" |
owedPencerequired | integer | Integer pence (GBP). |
overduePencerequired | integer | Integer pence (GBP). |
unpaidInvoicesrequired | integer | |
overdueInvoicesrequired | integer | |
draftsrequired | integer | |
remindersToApproverequired | integer | Reminders waiting for the owner to approve. |
debtorsrequired | array of SalesDebtor | Most overdue first. |
debtors[].customerIdrequired | string (uuid) | |
debtors[].customerNamerequired | string | |
debtors[].owedPencerequired | integer | Integer pence (GBP). |
debtors[].overduePencerequired | integer | Integer pence (GBP). |
debtors[].invoicesrequired | integer | |
debtors[].oldestDaysOverduerequired | integer | Days the oldest unpaid invoice is past due (0 if none is). |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Get the invoice settings
GET/api/v1/books/sales/settings
- Scopes
books:read
Address, contact and bank details printed on invoices, the brand colour and logo, VAT rounding, terms, numbering and reminders. Part of the books product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (SalesSettings).
What the business’s invoices say about it and how they look.
| Field | Type | Description |
|---|---|---|
addressLinesrequired | array of string | |
postcoderequired | stringnullable | |
emailrequired | stringnullable | Shown on invoices; customers’ replies go here. |
phonerequired | stringnullable | |
ownerNamesrequired | stringnullable | Sole traders and partnerships trading under a business name: the owner’s or partners’ names (Companies Act 2006 s1202). |
bankAccountNamerequired | stringnullable | |
bankSortCoderequired | stringnullable | example "123456" |
bankAccountNumberrequired | stringnullable | example "12345678" |
brandColourrequired | stringnullable | The accent colour on the business’s invoices; null for Tolvi’s. example "#1F4E79" |
logoStatusrequired | string (SalesLogoStatus) | available: the logo is on invoices. pending_scan: a new logo is being checked for viruses. One of: |
vatRoundingrequired | string (VatRounding) | VAT Notice 700 section 17: invoice (total VAT rounded down, para 17.5) or line (each line to the nearest penny, para 17.6). One of: |
defaultTermsDaysrequired | integer | 0 to 365 |
footerNoterequired | stringnullable | |
remindersOnrequired | boolean | Draft reminders for overdue invoices. The owner still approves each one. |
invoicePrefixrequired | string | example "INV-" |
creditNotePrefixrequired | string | example "CN-" |
numberingChangeablerequired | boolean | Whether the numbering can still change (nothing issued yet). |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Change the invoice settings
PATCH/api/v1/books/sales/settings
- Scopes
books:write
The business’s owners and admins, or a practice whose link can post. The numbering prefixes can change only until something has been issued (409 after), so numbers always run in one sequence. Part of the books product: the firm must have it and you must have access to it.
Request body
Required. application/json: object (SalesSettingsPatch).
| Field | Type | Description |
|---|---|---|
addressLines | array of string | |
postcode | stringnullable | |
email | stringnullable | |
phone | stringnullable | |
ownerNames | stringnullable | |
bankAccountName | stringnullable | |
bankSortCode | stringnullable | |
bankAccountNumber | stringnullable | |
brandColour | stringnullable | |
vatRounding | string (VatRounding) | VAT Notice 700 section 17: invoice (total VAT rounded down, para 17.5) or line (each line to the nearest penny, para 17.6). One of: |
defaultTermsDays | integer | 0 to 365 |
footerNote | stringnullable | |
remindersOn | boolean | |
invoicePrefix | string | |
creditNotePrefix | string |
Responses
200 OK, application/json
Body: object (SalesSettings).
What the business’s invoices say about it and how they look.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Get a short-lived link to the logo
GET/api/v1/books/sales/settings/logo
- Scopes
books:read
Null when there is no logo, or it is still being checked. Part of the books product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (SalesLogoLink).
| Field | Type | Description |
|---|---|---|
urlrequired | string (uri)nullable | A short-lived link to the logo, or null when there is none. |
contentTyperequired | stringnullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Start uploading a logo
POST/api/v1/books/sales/settings/logo
- Scopes
books:write
A PNG or JPEG up to 512 KB. PUT the image to the URL with exactly the headers given, then call logo/complete. Part of the books product: the firm must have it and you must have access to it.
Request body
Required. application/json: object (SalesLogoUploadRequest).
| Field | Type | Description |
|---|---|---|
contentTyperequired | string (SalesLogoType) | One of: |
sizeBytesrequired | integer | 1 to 524288 |
Responses
200 OK, application/json
Body: object (SalesLogoUpload).
| Field | Type | Description |
|---|---|---|
uploadrequired | object (PresignedUpload) | |
upload.urlrequired | string (uri) | |
upload.methodrequired | string (PresignedMethod) | One of: |
upload.headersrequired | object | Headers to send with the request. |
upload.expiresAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Take the logo off invoices
DELETE/api/v1/books/sales/settings/logo
- Scopes
books:write
Part of the books product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (SalesSettings).
What the business’s invoices say about it and how they look.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Finish uploading a logo
POST/api/v1/books/sales/settings/logo/complete
- Scopes
books:write
Checks the stored image and scans it for viruses. It goes on invoices once it is clean (logoStatus available). 422 if it is refused. Part of the books product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (SalesSettings).
What the business’s invoices say about it and how they look.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Get a customer’s statement
GET/api/v1/books/customers/{id}/statement
- Scopes
books:read
Every issued invoice still owed at the date, with ageing that adds up to the total, and the email as it would go. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
asAt | query | string (date) | Defaults to today. |
Responses
200 OK, application/json
Body: object (SalesStatement).
What a customer owes at a date, invoice by invoice, with ageing.
| Field | Type | Description |
|---|---|---|
customerIdrequired | string (uuid) | |
customerNamerequired | string | |
asAtrequired | string (date) | example "2026-03-31" |
itemsrequired | array of SalesStatementItem | |
items[].documentIdrequired | string (uuid) | |
items[].referencerequired | string | |
items[].daterequired | string (date) | example "2026-03-31" |
items[].dueDaterequired | string (date)nullable | example "2026-03-31" |
items[].daysOverduerequired | integer | |
items[].bucketrequired | string | example "days_1_30" |
items[].amountPencerequired | integer | Integer pence (GBP). |
items[].openPencerequired | integer | Integer pence (GBP). |
ageingrequired | object (SalesStatementAgeing) | |
ageing.currentrequired | integer | |
ageing.days_1_30required | integer | |
ageing.days_31_60required | integer | |
ageing.days_61_90required | integer | |
ageing.over_90required | integer | |
totalPencerequired | integer | Integer pence (GBP). |
emailDraftrequired | object (SalesStatementEmailDraft) | The email as it would go, for the owner to read and change first. |
emailDraft.torequired | stringnullable | |
emailDraft.subjectrequired | string | |
emailDraft.linesrequired | array of string | The paragraphs of the email. A message of the owner’s own goes after the first. |
emailDraft.fileNamerequired | string | |
lastSentrequired | object (SalesStatementSend)nullable | The last time a statement was emailed to them. |
lastSent.sentTorequired | string | |
lastSent.asAtrequired | string (date) | example "2026-03-31" |
lastSent.totalPencerequired | integer | Integer pence (GBP). |
lastSent.sentAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get a customer’s statement as a PDF
GET/api/v1/books/customers/{id}/statement/pdf
- Scopes
books:read
As the customer receives it, with the business’s logo and colour. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
asAt | query | string (date) | Defaults to today. |
Responses
200 OK, application/pdf
The PDF
Body: string (binary).
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Email a customer their statement
POST/api/v1/books/customers/{id}/statement/send
- Scopes
books:write- Access
- A signed-in Tolvi session only, never an API token.
To the customer (or the address given), with the PDF attached, from Tolvi in the business’s name; replies go to the business. Only a person at the business, signed in: never an accountant in the books, an API client or an assistant. 409 if they owe nothing. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Request body
Optional. application/json: object (SalesStatementSendInput).
| Field | Type | Description |
|---|---|---|
to | string | Defaults to the customer’s email. |
subject | string | up to 200 characters |
message | stringnullable | A short note added to the standard wording. up to 2000 characters |
asAt | string (date) | Defaults to today. example "2026-03-31" |
Responses
200 OK, application/json
Body: object (SalesStatement).
What a customer owes at a date, invoice by invoice, with ageing.
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).
List customers
GET/api/v1/books/customers
- Scopes
books:read
By name, with what each owes. archived=true lists archived customers instead. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
archived | query | string | One of: |
search | query | any |
Responses
200 OK, application/json
Body: object (CustomerList).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of Customer | |
items[].idrequired | string (uuid) | |
items[].namerequired | string | |
items[].emailrequired | stringnullable | |
items[].addressLinesrequired | array of string | |
items[].postcoderequired | stringnullable | |
items[].countryrequired | string | example "GB" |
items[].vatNumberrequired | stringnullable | Checked for format and check digits; only HMRC can confirm it is registered. example "GB123456789" |
items[].isBusinessrequired | boolean | |
items[].paymentTermsDaysrequired | integernullable | Days to pay; null means the business’s usual terms. |
items[].cisRegisteredrequired | boolean | |
items[].endUserOrIntermediaryrequired | boolean | |
items[].remindersPausedrequired | boolean | |
items[].archivedrequired | boolean | |
items[].owedPencerequired | integer | Still owed on issued invoices, in pence. |
items[].overduePencerequired | integer | Integer pence (GBP). Of that, past its due date. |
items[].createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Add a customer
POST/api/v1/books/customers
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
A UK VAT number must pass HMRC’s check digits (422 if not). Only HMRC can confirm a number is registered. Part of the books 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 (CustomerInput).
| Field | Type | Description |
|---|---|---|
namerequired | string | up to 200 characters |
email | stringnullable | |
addressLines | array of string | |
postcode | stringnullable | |
country | string | example "GB" |
vatNumber | stringnullable | |
isBusiness | boolean | |
paymentTermsDays | integernullable | |
cisRegistered | boolean | |
endUserOrIntermediary | boolean | |
remindersPaused | boolean |
Responses
201 Created, application/json
Body: object (Customer).
Someone the business invoices.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
namerequired | string | |
emailrequired | stringnullable | |
addressLinesrequired | array of string | |
postcoderequired | stringnullable | |
countryrequired | string | example "GB" |
vatNumberrequired | stringnullable | Checked for format and check digits; only HMRC can confirm it is registered. example "GB123456789" |
isBusinessrequired | boolean | |
paymentTermsDaysrequired | integernullable | Days to pay; null means the business’s usual terms. |
cisRegisteredrequired | boolean | |
endUserOrIntermediaryrequired | boolean | |
remindersPausedrequired | boolean | |
archivedrequired | boolean | |
owedPencerequired | integer | Still owed on issued invoices, in pence. |
overduePencerequired | integer | Integer pence (GBP). Of that, past its due date. |
createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 409 Conflict, 422 Unprocessable content, 429 Too many requests, as problem details (application/problem+json).
Get a customer
GET/api/v1/books/customers/{id}
- Scopes
books:read
Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (Customer).
Someone the business invoices.
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).
Change a customer
PATCH/api/v1/books/customers/{id}
- Scopes
books:write
Invoices already issued keep the details they were issued with. Part of the books 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 (CustomerPatch).
| Field | Type | Description |
|---|---|---|
name | string | up to 200 characters |
email | stringnullable | |
addressLines | array of string | |
postcode | stringnullable | |
country | string | |
vatNumber | stringnullable | |
isBusiness | boolean | |
paymentTermsDays | integernullable | |
cisRegistered | boolean | |
endUserOrIntermediary | boolean | |
remindersPaused | boolean |
Responses
200 OK, application/json
Body: object (Customer).
Someone the business invoices.
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).
Archive a customer
POST/api/v1/books/customers/{id}/archive
- Scopes
books:write
Hidden from lists and new invoices. 409 while they still owe money. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (Customer).
Someone the business invoices.
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).
Restore an archived customer
POST/api/v1/books/customers/{id}/restore
- Scopes
books:write
Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (Customer).
Someone the business invoices.
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).
List invoices or credit notes
GET/api/v1/books/invoices
- Scopes
books:read
Newest first. Status is worked out from payments and credit notes as at today. Part of the books 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 200 |
customerId | query | string (uuid) | |
status | query | string | One of: |
kind | query | string | One of: |
Responses
200 OK, application/json
Body: object (SalesDocumentList).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of SalesDocument | |
items[].idrequired | string (uuid) | |
items[].kindrequired | string (SalesDocumentKind) | One of: |
items[].staterequired | string (SalesDocumentState) | draft: can be changed or deleted. issued: numbered, in the books and never changed. One of: |
items[].statusrequired | string (InvoiceStatus) | draft, sent (issued, nothing paid yet), part_paid, paid, overdue, or void (credited in full). One of: |
items[].numberrequired | stringnullable | example "INV-0001" |
items[].openingrequired | boolean | Issued before the books started and brought forward in the opening balances: it has its old number and no Tolvi copy to print or send. |
items[].customerIdrequired | string (uuid) | |
items[].customerNamerequired | string | |
items[].customerEmailrequired | stringnullable | |
items[].issueDaterequired | string (date)nullable | example "2026-03-31" |
items[].supplyDaterequired | string (date)nullable | example "2026-03-31" |
items[].taxPointrequired | string (date)nullable | The VAT tax point (VATA 1994 s6). example "2026-03-31" |
items[].dueDaterequired | string (date)nullable | example "2026-03-31" |
items[].termsDaysrequired | integernullable | |
items[].roundingrequired | string (VatRounding) | VAT Notice 700 section 17: invoice (total VAT rounded down, para 17.5) or line (each line to the nearest penny, para 17.6). One of: |
items[].referencerequired | stringnullable | |
items[].purchaseOrderrequired | stringnullable | |
items[].notesrequired | stringnullable | |
items[].creditsIdrequired | string (uuid)nullable | Credit notes: the invoice credited. |
items[].creditsNumberrequired | stringnullable | |
items[].reasonrequired | stringnullable | Credit notes: why. |
items[].linesrequired | array of SalesLine | |
items[].lines[].descriptionrequired | string | up to 300 characters |
items[].lines[].quantity | string | Up to 3 decimal places. Default 1. example "3" |
items[].lines[].unitPricePencerequired | integer | Price per unit before VAT, in pence. at least 0 |
items[].lines[].vatCoderequired | string (VatCode) | One of: |
items[].lines[].accountId | string (uuid)nullable | The income account; the business’s sales account when left out. |
items[].lines[].discount | object (SalesLineDiscount)nullable | |
items[].lines[].discount.kindrequired | string (SalesDiscountKind) | One of: |
items[].lines[].discount.bps | integer | percent: basis points (1000 = 10%). |
items[].lines[].discount.pence | integer | amount: pence off the line. |
items[].lines[].unitCode | stringnullable | UN/ECE Recommendation 20 unit code. example "DAY" |
items[].lines[].cisLabour | boolean | CIS: labour (the deduction is worked on labour only). |
items[].lines[].netPencerequired | integer | Integer pence (GBP). After any discount, before VAT. |
items[].lines[].vatPencerequired | integer | Integer pence (GBP). VAT charged on the line (its share of the rounded total under invoice rounding). |
items[].lines[].rateBpsrequired | integer | Basis points (2000 = 20%). |
items[].totalsrequired | object (SalesTotals) | |
items[].totals.netPencerequired | integer | Integer pence (GBP). |
items[].totals.vatPencerequired | integer | Integer pence (GBP). |
items[].totals.grossPencerequired | integer | Integer pence (GBP). |
items[].totals.amountDuePencerequired | integer | Integer pence (GBP). What the customer pays: the gross less any CIS deduction. |
items[].totals.notionalVatPencerequired | integer | Integer pence (GBP). |
items[].totals.cisDeductionPencerequired | integer | Integer pence (GBP). |
items[].totals.byVatCoderequired | array of SalesVatTotal | |
items[].totals.byVatCode[].coderequired | string (VatCode) | One of: |
items[].totals.byVatCode[].rateBpsrequired | integer | |
items[].totals.byVatCode[].netPencerequired | integer | Integer pence (GBP). |
items[].totals.byVatCode[].vatPencerequired | integer | Integer pence (GBP). |
items[].totals.byVatCode[].notionalVatPencerequired | integer | Integer pence (GBP). Reverse charge: the VAT the customer accounts for, shown but not charged. |
items[].paidPencerequired | integer | Integer pence (GBP). |
items[].creditedPencerequired | integer | Integer pence (GBP). |
items[].outstandingPencerequired | integer | Integer pence (GBP). Still owed (invoices); nil for drafts and credit notes. |
items[].daysOverduerequired | integer | |
items[].sentAtrequired | string (date-time)nullable | |
items[].sentTorequired | stringnullable | |
items[].ledgerEntryIdrequired | string (uuid)nullable | The ledger entry it posted. |
items[].aiSuggestionIdrequired | string (uuid)nullable | Drafted from a sentence by Tolvi AI. |
items[].issuedAtrequired | string (date-time)nullable | |
items[].createdAtrequired | string (date-time) | |
items[].updatedAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Start a draft invoice
POST/api/v1/books/invoices
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
A draft posts nothing and can be changed or deleted. Pass the Tolvi AI suggestion’s id as aiSuggestionId when the draft came from a sentence; saving it records that the person accepted the suggestion. Part of the books 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 (CreateSalesDocument).
| Field | Type | Description |
|---|---|---|
customerIdrequired | string (uuid) | |
issueDate | string (date)nullable | example "2026-03-31" |
supplyDate | string (date)nullable | example "2026-03-31" |
dueDate | string (date)nullable | example "2026-03-31" |
termsDays | integernullable | |
lines | array of SalesLineInput | |
lines[].descriptionrequired | string | up to 300 characters |
lines[].quantity | string | Up to 3 decimal places. Default 1. example "3" |
lines[].unitPricePencerequired | integer | Price per unit before VAT, in pence. at least 0 |
lines[].vatCoderequired | string (VatCode) | One of: |
lines[].accountId | string (uuid)nullable | The income account; the business’s sales account when left out. |
lines[].discount | object (SalesLineDiscount)nullable | |
lines[].discount.kindrequired | string (SalesDiscountKind) | One of: |
lines[].discount.bps | integer | percent: basis points (1000 = 10%). |
lines[].discount.pence | integer | amount: pence off the line. |
lines[].unitCode | stringnullable | UN/ECE Recommendation 20 unit code. example "DAY" |
lines[].cisLabour | boolean | CIS: labour (the deduction is worked on labour only). |
reference | stringnullable | |
purchaseOrder | stringnullable | |
notes | stringnullable | |
aiSuggestionId | string (uuid)nullable | The Tolvi AI suggestion it was drafted from. |
Responses
201 Created, application/json
Body: object (SalesDocumentDetail).
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
kindrequired | string (SalesDocumentKind) | One of: |
staterequired | string (SalesDocumentState) | draft: can be changed or deleted. issued: numbered, in the books and never changed. One of: |
statusrequired | string (InvoiceStatus) | draft, sent (issued, nothing paid yet), part_paid, paid, overdue, or void (credited in full). One of: |
numberrequired | stringnullable | example "INV-0001" |
openingrequired | boolean | Issued before the books started and brought forward in the opening balances: it has its old number and no Tolvi copy to print or send. |
customerIdrequired | string (uuid) | |
customerNamerequired | string | |
customerEmailrequired | stringnullable | |
issueDaterequired | string (date)nullable | example "2026-03-31" |
supplyDaterequired | string (date)nullable | example "2026-03-31" |
taxPointrequired | string (date)nullable | The VAT tax point (VATA 1994 s6). example "2026-03-31" |
dueDaterequired | string (date)nullable | example "2026-03-31" |
termsDaysrequired | integernullable | |
roundingrequired | string (VatRounding) | VAT Notice 700 section 17: invoice (total VAT rounded down, para 17.5) or line (each line to the nearest penny, para 17.6). One of: |
referencerequired | stringnullable | |
purchaseOrderrequired | stringnullable | |
notesrequired | stringnullable | |
creditsIdrequired | string (uuid)nullable | Credit notes: the invoice credited. |
creditsNumberrequired | stringnullable | |
reasonrequired | stringnullable | Credit notes: why. |
linesrequired | array of SalesLine | |
lines[].descriptionrequired | string | up to 300 characters |
lines[].quantity | string | Up to 3 decimal places. Default 1. example "3" |
lines[].unitPricePencerequired | integer | Price per unit before VAT, in pence. at least 0 |
lines[].vatCoderequired | string (VatCode) | One of: |
lines[].accountId | string (uuid)nullable | The income account; the business’s sales account when left out. |
lines[].discount | object (SalesLineDiscount)nullable | |
lines[].discount.kindrequired | string (SalesDiscountKind) | One of: |
lines[].discount.bps | integer | percent: basis points (1000 = 10%). |
lines[].discount.pence | integer | amount: pence off the line. |
lines[].unitCode | stringnullable | UN/ECE Recommendation 20 unit code. example "DAY" |
lines[].cisLabour | boolean | CIS: labour (the deduction is worked on labour only). |
lines[].netPencerequired | integer | Integer pence (GBP). After any discount, before VAT. |
lines[].vatPencerequired | integer | Integer pence (GBP). VAT charged on the line (its share of the rounded total under invoice rounding). |
lines[].rateBpsrequired | integer | Basis points (2000 = 20%). |
totalsrequired | object (SalesTotals) | |
totals.netPencerequired | integer | Integer pence (GBP). |
totals.vatPencerequired | integer | Integer pence (GBP). |
totals.grossPencerequired | integer | Integer pence (GBP). |
totals.amountDuePencerequired | integer | Integer pence (GBP). What the customer pays: the gross less any CIS deduction. |
totals.notionalVatPencerequired | integer | Integer pence (GBP). |
totals.cisDeductionPencerequired | integer | Integer pence (GBP). |
totals.byVatCoderequired | array of SalesVatTotal | |
totals.byVatCode[].coderequired | string (VatCode) | One of: |
totals.byVatCode[].rateBpsrequired | integer | |
totals.byVatCode[].netPencerequired | integer | Integer pence (GBP). |
totals.byVatCode[].vatPencerequired | integer | Integer pence (GBP). |
totals.byVatCode[].notionalVatPencerequired | integer | Integer pence (GBP). Reverse charge: the VAT the customer accounts for, shown but not charged. |
paidPencerequired | integer | Integer pence (GBP). |
creditedPencerequired | integer | Integer pence (GBP). |
outstandingPencerequired | integer | Integer pence (GBP). Still owed (invoices); nil for drafts and credit notes. |
daysOverduerequired | integer | |
sentAtrequired | string (date-time)nullable | |
sentTorequired | stringnullable | |
ledgerEntryIdrequired | string (uuid)nullable | The ledger entry it posted. |
aiSuggestionIdrequired | string (uuid)nullable | Drafted from a sentence by Tolvi AI. |
issuedAtrequired | string (date-time)nullable | |
createdAtrequired | string (date-time) | |
updatedAtrequired | string (date-time) | |
supplierrequired | object (SalesParty) | A business or customer as the document shows it (frozen at issue). |
supplier.namerequired | string | |
supplier.addressLinesrequired | array of string | |
supplier.postcoderequired | stringnullable | |
supplier.vatNumberrequired | stringnullable | |
supplier.emailrequired | stringnullable | |
supplier.registeredNamerequired | stringnullable | Companies and LLPs: the registered name. |
supplier.companyNumberrequired | stringnullable | |
supplier.payTorequired | stringnullable | How to pay, as printed (the business only). |
customerrequired | object (SalesParty) | A business or customer as the document shows it (frozen at issue). |
customer.namerequired | string | |
customer.addressLinesrequired | array of string | |
customer.postcoderequired | stringnullable | |
customer.vatNumberrequired | stringnullable | |
customer.emailrequired | stringnullable | |
customer.registeredNamerequired | stringnullable | Companies and LLPs: the registered name. |
customer.companyNumberrequired | stringnullable | |
customer.payTorequired | stringnullable | How to pay, as printed (the business only). |
problemsrequired | array of SalesProblem | Drafts: what stops it being issued (errors) and what to check (warnings). |
problems[].coderequired | string | example "customer_address_missing" |
problems[].severityrequired | string (SalesProblemSeverity) | One of: |
problems[].fieldrequired | stringnullable | example "customer.address" |
problems[].messagerequired | string | |
problems[].citationrequired | stringnullable | The legislation or HMRC guidance. |
paymentsrequired | array of SalesPayment | |
payments[].idrequired | string (uuid) | |
payments[].paidOnrequired | string (date) | example "2026-03-31" |
payments[].amountPencerequired | integer | Integer pence (GBP). |
payments[].methodrequired | string (SalesPaymentMethod) | One of: |
payments[].accountIdrequired | string (uuid) | |
payments[].referencerequired | stringnullable | |
payments[].bankLineIdrequired | string (uuid)nullable | Set when it came from a matched bank line. |
payments[].ledgerEntryIdrequired | string (uuid) | |
payments[].createdAtrequired | string (date-time) | |
creditNotesrequired | array of SalesCreditApplied | |
creditNotes[].idrequired | string (uuid) | |
creditNotes[].numberrequired | stringnullable | |
creditNotes[].staterequired | string (SalesDocumentState) | draft: can be changed or deleted. issued: numbered, in the books and never changed. One of: |
creditNotes[].issueDaterequired | string (date)nullable | example "2026-03-31" |
creditNotes[].amountPencerequired | integer | Integer pence (GBP). What it takes off the invoice. |
creditNotes[].reasonrequired | stringnullable | |
sendsrequired | array of SalesSend | |
sends[].kindrequired | string (SalesSendKind) | One of: |
sends[].sentTorequired | string | |
sends[].subjectrequired | string | |
sends[].sentAtrequired | string (date-time) | |
remindersrequired | array of SalesReminder | |
reminders[].idrequired | string (uuid) | |
reminders[].invoiceIdrequired | string (uuid) | |
reminders[].invoiceNumberrequired | string | |
reminders[].customerNamerequired | string | |
reminders[].customerEmailrequired | stringnullable | |
reminders[].tonerequired | string (ReminderTone) | One of: |
reminders[].daysOverduerequired | integer | Negative before the due date. |
reminders[].outstandingPencerequired | integer | Integer pence (GBP). |
reminders[].compensationPencerequired | integer | Integer pence (GBP). Fixed late payment compensation the owner may add (Late Payment of Commercial Debts (Interest) Act 1998 s5A); not added unless they choose to. |
reminders[].subjectrequired | string | |
reminders[].bodyrequired | string | |
reminders[].statusrequired | string (ReminderStatus) | One of: |
reminders[].draftedOnrequired | string (date) | example "2026-03-31" |
reminders[].sentAtrequired | string (date-time)nullable | |
reminders[].sentTorequired | stringnullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 409 Conflict, 422 Unprocessable content, 429 Too many requests, as problem details (application/problem+json).
Draft an invoice from a sentence (Tolvi AI)
POST/api/v1/books/invoices/draft-from-sentence
- Scopes
books:write
Tolvi AI reads a sentence such as "Invoice Acme for 3 days’ consulting at £450 plus VAT" and Tolvi builds a draft from your customers, VAT status and terms, with the questions to answer. A suggestion only: nothing is saved, issued or sent. Included in the Tolvi Books price. Needs a person; not available through MCP. Part of the books product: the firm must have it and you must have access to it.
Request body
Required. application/json: object (DraftInvoiceFromSentence).
| Field | Type | Description |
|---|---|---|
sentencerequired | string | up to 1000 characters; example "Invoice Acme for 3 days' consulting at £450 plus VAT" |
Responses
200 OK, application/json
Body: object (SalesDraftSuggestion).
What Tolvi AI made of the sentence: a suggestion to check and save as a draft. Nothing is saved, issued or sent.
| Field | Type | Description |
|---|---|---|
suggestionIdrequired | string (uuid) | The Tolvi AI suggestion; pass it as aiSuggestionId when saving the draft. |
customerMatchrequired | string (SalesCustomerMatch) | One of: |
customerIdrequired | string (uuid)nullable | |
customerNamerequired | stringnullable | |
customerEmailrequired | stringnullable | |
linesrequired | array of SalesLine | |
lines[].descriptionrequired | string | up to 300 characters |
lines[].quantity | string | Up to 3 decimal places. Default 1. example "3" |
lines[].unitPricePencerequired | integer | Price per unit before VAT, in pence. at least 0 |
lines[].vatCoderequired | string (VatCode) | One of: |
lines[].accountId | string (uuid)nullable | The income account; the business’s sales account when left out. |
lines[].discount | object (SalesLineDiscount)nullable | |
lines[].discount.kindrequired | string (SalesDiscountKind) | One of: |
lines[].discount.bps | integer | percent: basis points (1000 = 10%). |
lines[].discount.pence | integer | amount: pence off the line. |
lines[].unitCode | stringnullable | UN/ECE Recommendation 20 unit code. example "DAY" |
lines[].cisLabour | boolean | CIS: labour (the deduction is worked on labour only). |
lines[].netPencerequired | integer | Integer pence (GBP). After any discount, before VAT. |
lines[].vatPencerequired | integer | Integer pence (GBP). VAT charged on the line (its share of the rounded total under invoice rounding). |
lines[].rateBpsrequired | integer | Basis points (2000 = 20%). |
issueDaterequired | string (date) | example "2026-03-31" |
supplyDaterequired | string (date)nullable | example "2026-03-31" |
dueDaterequired | string (date)nullable | example "2026-03-31" |
termsDaysrequired | integernullable | |
purchaseOrderrequired | stringnullable | |
totalsrequired | object (SalesTotals) | |
totals.netPencerequired | integer | Integer pence (GBP). |
totals.vatPencerequired | integer | Integer pence (GBP). |
totals.grossPencerequired | integer | Integer pence (GBP). |
totals.amountDuePencerequired | integer | Integer pence (GBP). What the customer pays: the gross less any CIS deduction. |
totals.notionalVatPencerequired | integer | Integer pence (GBP). |
totals.cisDeductionPencerequired | integer | Integer pence (GBP). |
totals.byVatCoderequired | array of SalesVatTotal | |
totals.byVatCode[].coderequired | string (VatCode) | One of: |
totals.byVatCode[].rateBpsrequired | integer | |
totals.byVatCode[].netPencerequired | integer | Integer pence (GBP). |
totals.byVatCode[].vatPencerequired | integer | Integer pence (GBP). |
totals.byVatCode[].notionalVatPencerequired | integer | Integer pence (GBP). Reverse charge: the VAT the customer accounts for, shown but not charged. |
questionsrequired | array of SalesDraftQuestion | |
questions[].coderequired | string | example "customer_ambiguous" |
questions[].fieldrequired | string | |
questions[].messagerequired | string | |
questions[].blockingrequired | boolean | Must be answered before the invoice can be issued. |
questions[].optionsrequired | array of object | |
questions[].options[].idrequired | string | |
questions[].options[].labelrequired | string | |
assumptionsrequired | array of SalesDraftAssumption | |
assumptions[].fieldrequired | string | |
assumptions[].messagerequired | string | |
noterequired | string | Tolvi AI’s note on anything unclear, or "". |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Get an invoice or credit note
GET/api/v1/books/invoices/{id}
- Scopes
books:read
With its lines, totals, what is owed, payments, credit notes, emails sent and reminders. A draft lists what would stop it being issued. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Change a draft
PATCH/api/v1/books/invoices/{id}
- Scopes
books:write
409 once issued: an issued invoice is corrected with a credit note. Part of the books 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 (UpdateSalesDocument).
Change a draft. Fields left out keep their value.
| Field | Type | Description |
|---|---|---|
customerId | string (uuid) | |
issueDate | string (date)nullable | example "2026-03-31" |
supplyDate | string (date)nullable | example "2026-03-31" |
dueDate | string (date)nullable | example "2026-03-31" |
termsDays | integernullable | |
lines | array of SalesLineInput | |
lines[].descriptionrequired | string | up to 300 characters |
lines[].quantity | string | Up to 3 decimal places. Default 1. example "3" |
lines[].unitPricePencerequired | integer | Price per unit before VAT, in pence. at least 0 |
lines[].vatCoderequired | string (VatCode) | One of: |
lines[].accountId | string (uuid)nullable | The income account; the business’s sales account when left out. |
lines[].discount | object (SalesLineDiscount)nullable | |
lines[].discount.kindrequired | string (SalesDiscountKind) | One of: |
lines[].discount.bps | integer | percent: basis points (1000 = 10%). |
lines[].discount.pence | integer | amount: pence off the line. |
lines[].unitCode | stringnullable | UN/ECE Recommendation 20 unit code. example "DAY" |
lines[].cisLabour | boolean | CIS: labour (the deduction is worked on labour only). |
reference | stringnullable | |
purchaseOrder | stringnullable | |
notes | stringnullable | |
reason | stringnullable | Credit notes: why. |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Delete a draft
DELETE/api/v1/books/invoices/{id}
- Scopes
books:write
409 once issued: an issued invoice is never deleted, only cancelled with a credit note. Part of the books 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
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Copy an invoice as a new draft
POST/api/v1/books/invoices/{id}/duplicate
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
A new draft for the same customer with the same lines and note, undated (it takes the date it is issued) and on the customer’s usual terms. The order number isn’t copied. Credit notes can’t be copied. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | 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 |
Responses
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).
Issue an invoice or credit note
POST/api/v1/books/invoices/{id}/issue
- Scopes
books:write
Takes the next number in the series (no gaps: VAT Regulations 1995 reg 14(1)(a)) and posts it to the books, in one step. 422 with every reason when it can’t be issued (for example a missing customer address on a VAT invoice, or a locked period); nothing is numbered or posted then. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Request body
Optional. application/json: object (IssueSalesDocument).
| Field | Type | Description |
|---|---|---|
issueDate | string (date) | Defaults to the draft’s date, or today. example "2026-03-31" |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Draft a credit note for an issued invoice
POST/api/v1/books/invoices/{id}/credit-notes
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
The whole invoice unless lines are given, at the VAT rates of the original supply (VAT Notice 700 section 19). Issue the credit note to post it. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | 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 (CreditNoteRequest).
| Field | Type | Description |
|---|---|---|
reasonrequired | string | up to 300 characters |
lines | array of SalesLineInput | Leave out to credit the whole invoice. |
lines[].descriptionrequired | string | up to 300 characters |
lines[].quantity | string | Up to 3 decimal places. Default 1. example "3" |
lines[].unitPricePencerequired | integer | Price per unit before VAT, in pence. at least 0 |
lines[].vatCoderequired | string (VatCode) | One of: |
lines[].accountId | string (uuid)nullable | The income account; the business’s sales account when left out. |
lines[].discount | object (SalesLineDiscount)nullable | |
lines[].discount.kindrequired | string (SalesDiscountKind) | One of: |
lines[].discount.bps | integer | percent: basis points (1000 = 10%). |
lines[].discount.pence | integer | amount: pence off the line. |
lines[].unitCode | stringnullable | UN/ECE Recommendation 20 unit code. example "DAY" |
lines[].cisLabour | boolean | CIS: labour (the deduction is worked on labour only). |
issueDate | string (date) | example "2026-03-31" |
Responses
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).
Cancel an issued invoice
POST/api/v1/books/invoices/{id}/void
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
Issues a credit note for the whole invoice, so its number stays used and the books balance. 409 if anything has been paid or credited already (use a credit note instead). Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | 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 (VoidInvoiceRequest).
| Field | Type | Description |
|---|---|---|
reasonrequired | string | up to 300 characters |
issueDate | string (date) | example "2026-03-31" |
Responses
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).
Record a payment received
POST/api/v1/books/invoices/{id}/payments
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
Posts it to the books (into the bank or cash account given, out of money owed to you). No more than is still owed; not dated in the future. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | 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 (RecordSalesPayment).
| Field | Type | Description |
|---|---|---|
paidOnrequired | string (date) | example "2026-03-31" |
amountPencerequired | integer | Integer pence (GBP). at least 1 |
method | string (SalesPaymentMethod) | One of: |
accountIdrequired | string (uuid) | The bank or cash account the money went into. |
reference | stringnullable |
Responses
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).
Get the PDF
GET/api/v1/books/invoices/{id}/pdf
- Scopes
books:read
As the customer receives it, with the business’s logo and colour. A draft is marked DRAFT. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/pdf
The PDF
Body: string (binary).
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Email an issued invoice or credit note
POST/api/v1/books/invoices/{id}/send
- Scopes
books:write- Access
- A signed-in Tolvi session only, never an API token.
To the customer (or the address given), with the PDF attached, from Tolvi in the business’s name; replies go to the business. Only a person at the business, signed in: never an accountant in the books, an API client or an assistant. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Request body
Optional. application/json: object (SendSalesDocument).
| Field | Type | Description |
|---|---|---|
to | string | Defaults to the customer’s email. |
subject | string | The email’s subject. Defaults to "Invoice INV-0001 from <business>" (or "Credit note …"). up to 200 characters |
message | stringnullable | up to 2000 characters |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
List payment reminders
GET/api/v1/books/reminders
- Scopes
books:read
Drafted by Tolvi for overdue (or nearly due) invoices; nothing is sent until a person at the business approves it. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
invoiceId | query | string (uuid) | |
status | query | string | One of: |
Responses
200 OK, application/json
Body: object (SalesReminderList).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of SalesReminder | |
items[].idrequired | string (uuid) | |
items[].invoiceIdrequired | string (uuid) | |
items[].invoiceNumberrequired | string | |
items[].customerNamerequired | string | |
items[].customerEmailrequired | stringnullable | |
items[].tonerequired | string (ReminderTone) | One of: |
items[].daysOverduerequired | integer | Negative before the due date. |
items[].outstandingPencerequired | integer | Integer pence (GBP). |
items[].compensationPencerequired | integer | Integer pence (GBP). Fixed late payment compensation the owner may add (Late Payment of Commercial Debts (Interest) Act 1998 s5A); not added unless they choose to. |
items[].subjectrequired | string | |
items[].bodyrequired | string | |
items[].statusrequired | string (ReminderStatus) | One of: |
items[].draftedOnrequired | string (date) | example "2026-03-31" |
items[].sentAtrequired | string (date-time)nullable | |
items[].sentTorequired | stringnullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Edit a reminder before sending it
PATCH/api/v1/books/reminders/{id}
- Scopes
books:write- Access
- A signed-in Tolvi session only, never an API token.
A person at the business, signed in. Part of the books 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 (UpdateSalesReminder).
| Field | Type | Description |
|---|---|---|
subjectrequired | string | up to 200 characters |
bodyrequired | string | up to 5000 characters |
Responses
200 OK, application/json
Body: object (SalesReminder).
A reminder drafted for an overdue (or nearly due) invoice. It goes only when a person at the business presses Send.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
invoiceIdrequired | string (uuid) | |
invoiceNumberrequired | string | |
customerNamerequired | string | |
customerEmailrequired | stringnullable | |
tonerequired | string (ReminderTone) | One of: |
daysOverduerequired | integer | Negative before the due date. |
outstandingPencerequired | integer | Integer pence (GBP). |
compensationPencerequired | integer | Integer pence (GBP). Fixed late payment compensation the owner may add (Late Payment of Commercial Debts (Interest) Act 1998 s5A); not added unless they choose to. |
subjectrequired | string | |
bodyrequired | string | |
statusrequired | string (ReminderStatus) | One of: |
draftedOnrequired | string (date) | example "2026-03-31" |
sentAtrequired | string (date-time)nullable | |
sentTorequired | stringnullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Approve and send a reminder
POST/api/v1/books/reminders/{id}/send
- Scopes
books:write- Access
- A signed-in Tolvi session only, never an API token.
Emails it to the customer as it stands. Only a person at the business, signed in; 409 if the invoice has been paid. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SalesReminder).
A reminder drafted for an overdue (or nearly due) invoice. It goes only when a person at the business presses Send.
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).
Dismiss a reminder
POST/api/v1/books/reminders/{id}/dismiss
- Scopes
books:write- Access
- A signed-in Tolvi session only, never an API token.
Not sent. The schedule moves on to the next step. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SalesReminder).
A reminder drafted for an overdue (or nearly due) invoice. It goes only when a person at the business presses Send.
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).
List repeating invoices
GET/api/v1/books/recurring-invoices
- Scopes
books:read
By default those still running or paused. invoiceId finds the one an invoice was set up from, or made by. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
customerId | query | string (uuid) | |
invoiceId | query | string (uuid) | |
status | query | string | One of: |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoiceList).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of SalesRecurringInvoice | |
items[].idrequired | string (uuid) | |
items[].customerIdrequired | string (uuid) | |
items[].customerNamerequired | string | |
items[].customerEmailrequired | stringnullable | |
items[].sourceDocumentIdrequired | string (uuid)nullable | The invoice it was set up from. |
items[].frequencyrequired | string (SalesRepeatFrequency) | One of: |
items[].frequencyTextrequired | string | example "every month" |
items[].statusrequired | string (SalesRepeatStatus) | active: makes one on nextOn. paused: makes none until resumed. stopped: for good. One of: |
items[].nextOnrequired | string (date)nullable | The next date one is made. Null when paused or stopped. example "2026-03-31" |
items[].firstOnrequired | string (date) | example "2026-03-31" |
items[].autoSendrequired | boolean | false (the default): each one is a draft for the owner to check. true: issued and emailed on the day, in the name of the person who turned it on. |
items[].autoSendAtrequired | string (date-time)nullable | |
items[].amountPencerequired | integer | What each one bills, with VAT, in pence. |
items[].summaryrequired | string | The first line’s description, to recognise it by. |
items[].lineCountrequired | integer | |
items[].runCountrequired | integer | |
items[].lastRunOnrequired | string (date)nullable | example "2026-03-31" |
items[].lastDocumentIdrequired | string (uuid)nullable | The last invoice made. |
items[].lastProblemrequired | stringnullable | What went wrong on the last run, in plain words. |
items[].createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Repeat an invoice
POST/api/v1/books/recurring-invoices
- Scopes
books:write- Retries
- Send an
Idempotency-Keyto make retries safe.
Copies the invoice’s customer, lines, note and terms. On each date Tolvi makes a new draft for the owner to check: nothing is numbered, posted or sent. 409 if the invoice already repeats. Part of the books 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 (SalesRecurringInvoiceInput).
| Field | Type | Description |
|---|---|---|
invoiceIdrequired | string (uuid) | The invoice to repeat: its customer, lines, note and terms are copied. |
frequencyrequired | string (SalesRepeatFrequency) | One of: |
firstOnrequired | string (date) | The first date to make one. Today or later. example "2026-03-31" |
Responses
201 Created, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
customerIdrequired | string (uuid) | |
customerNamerequired | string | |
customerEmailrequired | stringnullable | |
sourceDocumentIdrequired | string (uuid)nullable | The invoice it was set up from. |
frequencyrequired | string (SalesRepeatFrequency) | One of: |
frequencyTextrequired | string | example "every month" |
statusrequired | string (SalesRepeatStatus) | active: makes one on nextOn. paused: makes none until resumed. stopped: for good. One of: |
nextOnrequired | string (date)nullable | The next date one is made. Null when paused or stopped. example "2026-03-31" |
firstOnrequired | string (date) | example "2026-03-31" |
autoSendrequired | boolean | false (the default): each one is a draft for the owner to check. true: issued and emailed on the day, in the name of the person who turned it on. |
autoSendAtrequired | string (date-time)nullable | |
amountPencerequired | integer | What each one bills, with VAT, in pence. |
summaryrequired | string | The first line’s description, to recognise it by. |
lineCountrequired | integer | |
runCountrequired | integer | |
lastRunOnrequired | string (date)nullable | example "2026-03-31" |
lastDocumentIdrequired | string (uuid)nullable | The last invoice made. |
lastProblemrequired | stringnullable | What went wrong on the last run, in plain words. |
createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 409 Conflict, 422 Unprocessable content, 429 Too many requests, as problem details (application/problem+json).
Get a repeating invoice
GET/api/v1/books/recurring-invoices/{id}
- Scopes
books:read
Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
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).
Change a repeating invoice
PATCH/api/v1/books/recurring-invoices/{id}
- Scopes
books:write
How often, the next date (later dates follow from it), or what it bills, copied from another invoice for the same customer. Invoices already made don’t change. Part of the books 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 (SalesRecurringInvoicePatch).
| Field | Type | Description |
|---|---|---|
frequency | string (SalesRepeatFrequency) | One of: |
nextOn | string (date) | The next date to make one. Today or later; later dates follow from it. example "2026-03-31" |
fromInvoiceId | string (uuid) | Bill what this invoice bills from now on: its lines, note and terms (same customer). |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
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).
Turn automatic sending on or off
POST/api/v1/books/recurring-invoices/{id}/auto-send
- Scopes
books:write- Access
- A signed-in Tolvi session only, never an API token.
On: each invoice is issued and emailed on its date, without anyone checking it, in the name of the person who turned this on. Only a person at the business, signed in: never an accountant in the books, an API client or an assistant. If anything is in the way the invoice stays a draft, and the schedule says why. Part of the books 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 (SalesRecurringAutoSend).
| Field | Type | Description |
|---|---|---|
onrequired | boolean | true: issue and email each one on the day. false: each one is a draft to check. |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
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).
Pause a repeating invoice
POST/api/v1/books/recurring-invoices/{id}/pause
- Scopes
books:write
No more are made until it is resumed. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
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).
Resume a paused repeating invoice
POST/api/v1/books/recurring-invoices/{id}/resume
- Scopes
books:write
From its next date on or after today. Dates missed while it was paused aren’t billed. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
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).
Stop a repeating invoice
POST/api/v1/books/recurring-invoices/{id}/stop
- Scopes
books:write
For good. Invoices already made stay as they are. Part of the books product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SalesRecurringInvoice).
A repeating invoice: what it bills, how often, and when the next one is made.
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).