Skip to main content

Billing

21 operations in the Tolvi API, version 1. Paths are relative to https://api.tolvi.co.uk. Every amount is integer pence.

Get the firm’s billing account, plan and this period’s engagements

GET/api/v1/billing/account

Scopes
settings:admin
Role
Firm admin

Responses

200 OK, application/json

Body: object (BillingAccount).

200 OK response for GET /api/v1/billing/account
FieldTypeDescription
statusrequiredstring

trialing, trial_ended, or the Stripe subscription status.

stripeCustomerIdrequiredstringnullable
hasSubscriptionrequiredboolean
planIdrequiredstringnullable
planIntervalrequiredstringnullable
trialEndsAtrequiredstring (date-time)
freeEngagementsrequiredinteger
freeEngagementsUsedrequiredinteger
dunningSincerequiredstring (date-time)nullable

When an invoice first failed; starting engagements is blocked 14 days after.

startBlockedrequiredboolean
startBlockedReasonrequiredstringnullable
billingEmailrequiredstringnullable
vatNumberrequiredstringnullable
planrequiredobject (BillingPlan)
plan.​versionrequiredstring
plan.​statusrequiredstring (PriceTableStatus)

One of: draft, confirmed

plan.​currencyrequiredstring
plan.​tiersrequiredarray of PriceTier
plan.​tiers[].​upTorequiredintegernullable

Inclusive upper bound (engagements per month); null for the last tier.

plan.​tiers[].​unitPencerequiredinteger

Pence per engagement, net of VAT.

plan.​trialDaysrequiredinteger
plan.​freeEngagementsrequiredinteger
plan.​cancellationDaysrequiredinteger
plan.​dunningBlockDaysrequiredinteger
plan.​example100requiredinteger

What 100 engagements in a month cost, in pence.

periodrequiredobject (BillingPeriod)
period.​startedrequiredinteger
period.​creditedrequiredinteger
period.​freerequiredinteger
period.​billablerequiredinteger
period.​estimaterequiredobject (BillingEstimate)
period.​estimate.​totalPencerequiredinteger

Integer pence (GBP).

period.​estimate.​linesrequiredarray of TierLine
period.​estimate.​lines[].​fromrequiredinteger
period.​estimate.​lines[].​torequiredinteger
period.​estimate.​lines[].​countrequiredinteger
period.​estimate.​lines[].​unitPencerequiredinteger

Integer pence (GBP).

period.​estimate.​lines[].​amountPencerequiredinteger

Integer pence (GBP).

period.​fromrequiredstring (date-time)
period.​torequiredstring (date-time)
period.​nextUnitPencerequiredinteger

Integer pence (GBP).

Price of the next engagement this month.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Get the per-engagement tiers the plans are priced from

GET/api/v1/billing/plan

Scopes
settings:admin
Role
Firm admin

Graduated monthly tiers, as data.

Responses

200 OK, application/json

Body: object (BillingPlan).

200 OK response for GET /api/v1/billing/plan
FieldTypeDescription
versionrequiredstring
statusrequiredstring (PriceTableStatus)

One of: draft, confirmed

currencyrequiredstring
tiersrequiredarray of PriceTier
tiers[].​upTorequiredintegernullable

Inclusive upper bound (engagements per month); null for the last tier.

tiers[].​unitPencerequiredinteger

Pence per engagement, net of VAT.

trialDaysrequiredinteger
freeEngagementsrequiredinteger
cancellationDaysrequiredinteger
dunningBlockDaysrequiredinteger
example100requiredinteger

What 100 engagements in a month cost, in pence.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

List the plans with monthly and annual prices, allowances, AI tokens, overage rates and entitlements

GET/api/v1/billing/plans

Scopes
settings:admin
Role
Firm admin

Responses

200 OK, application/json

Body: object (PlanCatalogue).

200 OK response for GET /api/v1/billing/plans
FieldTypeDescription
versionrequiredstring
statusrequiredstring (PlanCatalogueStatus)

One of: draft, confirmed

currencyrequiredstring
annualDiscountBpsrequiredinteger
vatRegisteredrequiredboolean

Whether Tolvi charges VAT on these prices. False: no VAT is charged; true: VAT is added at checkout and on invoices.

tiersrequiredarray of PriceTier
tiers[].​upTorequiredintegernullable

Inclusive upper bound (engagements per month); null for the last tier.

tiers[].​unitPencerequiredinteger

Pence per engagement, net of VAT.

plansrequiredarray of PlanOption
plans[].​idrequiredstring (PlanId)

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

plans[].​namerequiredstring
plans[].​customrequiredboolean

Priced per firm (Enterprise).

plans[].​engagementsPerYearrequiredintegernullable
plans[].​monthlyPencerequiredintegernullable

Pence a month, billed monthly (list price), net of VAT.

plans[].​annualPencerequiredintegernullable

Pence a year, billed annually upfront (15% off).

plans[].​aiTokensPerMonthrequiredintegernullable
plans[].​overageMonthlyPencerequiredintegernullable

Integer pence (GBP).

plans[].​overageAnnualPencerequiredintegernullable

Integer pence (GBP).

plans[].​entitlementsrequiredobject (PlanEntitlements)
plans[].​entitlements.​ssorequiredboolean
plans[].​entitlements.​prioritySupportrequiredboolean
plans[].​entitlements.​assistedOnboardingrequiredboolean
plans[].​entitlements.​accountManagerrequiredboolean
plans[].​entitlements.​supportSlarequiredboolean
plans[].​entitlements.​multiOfficeReportingrequiredboolean
plans[].​entitlements.​apiRateLimitTierrequiredstring (ApiRateLimitTier)

One of: standard, high, custom

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Get the subscription: plan, interval, allowance used this plan year, AI tokens this month, next invoice, entitlements

GET/api/v1/billing/subscription

Scopes
settings:admin
Role
Firm admin

Responses

200 OK, application/json

Body: object (Subscription).

200 OK response for GET /api/v1/billing/subscription
FieldTypeDescription
statusrequiredstring

trialing, no_plan, or the Stripe subscription status.

planIdrequiredstring (PlanId)nullable

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

planNamerequiredstringnullable
intervalrequiredstring (PlanInterval)nullable

One of: month, year

pricePenceinteger

Integer pence (GBP).

mrrPenceinteger

Integer pence (GBP).

currentPeriodStartsAtstring (date-time)nullable
currentPeriodEndsAtstring (date-time)nullable
trialrequiredobject (TrialStatus)
trial.​endsAtrequiredstring (date-time)
trial.​freeEngagementsrequiredinteger
trial.​freeEngagementsUsedrequiredinteger
trial.​activerequiredboolean
allowancerequiredobject (PlanAllowance)nullable
allowance.​planYearStartsAtrequiredstring (date-time)
allowance.​planYearEndsAtrequiredstring (date-time)
allowance.​totalrequiredinteger
allowance.​usedrequiredinteger
allowance.​remainingrequiredinteger
allowance.​overagerequiredinteger
allowance.​overagePencerequiredinteger

Integer pence (GBP).

allowance.​overageRatePencerequiredinteger

Integer pence (GBP).

allowance.​thresholdsReachedrequiredarray of integer

80 and/or 100 once reached.

aiTokensrequiredobject (PlanAiTokens)
aiTokens.​monthrequiredstring

example "2026-10"

aiTokens.​includedrequiredinteger

Included with the plan this month (no rollover).

aiTokens.​usedrequiredinteger
nextInvoicerequiredobject (NextInvoice)nullable
nextInvoice.​daterequiredstring (date-time)nullable
nextInvoice.​planPencerequiredinteger

Integer pence (GBP).

nextInvoice.​overagePencerequiredinteger

Integer pence (GBP).

Overage not yet invoiced.

entitlementsrequiredobject (PlanEntitlements)
entitlements.​ssorequiredboolean
entitlements.​prioritySupportrequiredboolean
entitlements.​assistedOnboardingrequiredboolean
entitlements.​accountManagerrequiredboolean
entitlements.​supportSlarequiredboolean
entitlements.​multiOfficeReportingrequiredboolean
entitlements.​apiRateLimitTierrequiredstring (ApiRateLimitTier)

One of: standard, high, custom

cancelAtrequiredstring (date-time)nullable
scheduledChangerequiredobject (ScheduledPlanChange)nullable
scheduledChange.​planIdrequiredstring (PlanId)

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

scheduledChange.​intervalrequiredstring (PlanInterval)nullable

One of: month, year

scheduledChange.​effectiveAtrequiredstring (date-time)nullable
pendingChangeobject (PendingPlanChange)nullable

A plan chosen but not yet paid for: nothing is granted until Stripe reports the invoice paid.

pendingChange.​planIdrequiredstring (PlanId)

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

pendingChange.​intervalrequiredstring (PlanInterval)nullable

One of: month, year

pendingChange.​paymentUrlrequiredstringnullable

Stripe’s hosted page for paying the invoice.

recommendationrequiredstring (PlanId)nullable

The plan Tolvi recommends (allowance used up, or overage reaching the next plan’s price).

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Choose or change plan

POST/api/v1/billing/subscription

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

A first plan starts the subscription and plan year. Upgrades apply at once, prorated; downgrades are scheduled for renewal. Clears a pending cancellation.

Request body

Required. application/json: object (ChangePlan).

Request body for POST /api/v1/billing/subscription
FieldTypeDescription
planIdrequiredstring (PlanId)

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

intervalrequiredstring (PlanInterval)

One of: month, year

Responses

200 OK, application/json

Body: object (Subscription).

The fields are as shown above.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Preview a plan change

POST/api/v1/billing/subscription/preview

Scopes
settings:admin
Role
Firm admin

Upgrades apply now, prorated; downgrades at renewal.

Request body

Required. application/json: object (ChangePlan).

Request body for POST /api/v1/billing/subscription/preview
FieldTypeDescription
planIdrequiredstring (PlanId)

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

intervalrequiredstring (PlanInterval)

One of: month, year

Responses

200 OK, application/json

Body: object (PlanChangePreview).

200 OK response for POST /api/v1/billing/subscription/preview
FieldTypeDescription
kindrequiredstring (PlanChangeKind)

One of: new, upgrade, downgrade

effectiverequiredstring (PlanChangeEffective)

One of: now, renewal

effectiveAtrequiredstring (date-time)
planIdrequiredstring (PlanId)

One of: starter, solo, practice, growth, firm, scale, group, group_plus, enterprise

intervalrequiredstring (PlanInterval)

One of: month, year

pricePencerequiredinteger

Integer pence (GBP).

prorationPencerequiredinteger

Integer pence (GBP).

Charged now: the prorated difference for an upgrade (or the first period for a new plan).

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Get the Meetings tiers, the firm’s Meetings plan and this month’s minutes

GET/api/v1/billing/meetings

Scopes
settings:admin
Role
Firm admin

Responses

200 OK, application/json

Body: object (MeetingsBilling).

The Meetings tiers, the firm’s Meetings plan and this month’s minutes.

200 OK response for GET /api/v1/billing/meetings
FieldTypeDescription
catalogueVersionrequiredstring
vatRegisteredrequiredboolean
overagePencePerMinuterequiredinteger

at least 0

trialMinutesrequiredinteger

at least 0

plansrequiredarray of MeetingsPlan
plans[].​idrequiredstring (MeetingsPlanId)

One of: meetings_starter, meetings_solo, meetings_team, meetings_practice, meetings_firm

plans[].​namerequiredstring
plans[].​minutesPerMonthrequiredinteger

at least 0

plans[].​monthlyPencerequiredinteger

Pence, excluding VAT.

at least 0

plans[].​annualPencerequiredinteger

Pence, excluding VAT (15% off 12 months).

at least 0

subscribedrequiredboolean

The firm has a Tolvi subscription that Meetings is (or can be) part of. If not, Meetings is bought on its own through Checkout.

standalonerequiredboolean

Meetings is the firm’s only Tolvi subscription.

annualDiscountBpsrequiredinteger

Annual discount in basis points (1500 = 15%).

at least 0

pendingCheckoutUrlrequiredstring (uri)nullable

A Meetings Checkout started but not finished: send the browser here.

intervalrequiredstring (PlanInterval)nullable

Meetings bills at the subscription’s interval.

One of: month, year

statusrequiredstring (FirmProductStatus)nullable

Null: the firm doesn’t have Meetings.

One of: active, trial, suspended

planIdrequiredstring (MeetingsPlanId)nullable

Null on a trial.

One of: meetings_starter, meetings_solo, meetings_team, meetings_practice, meetings_firm

planNamerequiredstringnullable
scheduledChangerequiredobject (MeetingsScheduledChange)nullable
scheduledChange.​planIdrequiredstring (MeetingsPlanId)nullable

Null: Meetings ends.

One of: meetings_starter, meetings_solo, meetings_team, meetings_practice, meetings_firm

scheduledChange.​effectiveAtrequiredstring (date-time)nullable

The end of the current billing period.

usagerequiredobject (MeetingsUsageThisMonth)
usage.​monthrequiredstring

example "2026-10"

usage.​minutesUsedrequiredinteger

at least 0

usage.​allowancerequiredinteger

at least 0

usage.​remainingrequiredinteger

at least 0

usage.​overageMinutesrequiredinteger

at least 0

usage.​overagePencerequiredinteger

Pence, excluding VAT; billed in arrears on a paid plan.

at least 0

usage.​thresholdsReachedrequiredarray of number
recommendationrequiredstring (MeetingsPlanId)nullable

The overage has reached the next tier’s price.

One of: meetings_starter, meetings_solo, meetings_team, meetings_practice, meetings_firm

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Choose, change or cancel the Meetings plan

PUT/api/v1/billing/meetings

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

With a Tolvi subscription, Meetings is added to it at its interval: a first plan and upgrades apply at once, prorated, once the invoice is paid; downgrades and cancelling (planId null) apply at the end of the billing period. Without one, Meetings is bought on its own through Stripe Checkout (interval month or year; see pendingCheckoutUrl) and starts once the first invoice is paid.

Request body

Required. application/json: object (ChangeMeetingsPlan).

Request body for PUT /api/v1/billing/meetings
FieldTypeDescription
planIdrequiredstring (MeetingsPlanId)nullable

Null cancels Meetings at the end of the billing period.

One of: meetings_starter, meetings_solo, meetings_team, meetings_practice, meetings_firm

intervalstring (PlanInterval)

Only when buying Meetings on its own (no Tolvi subscription yet). Default month.

One of: month, year

Responses

200 OK, application/json

Body: object (MeetingsBilling).

The Meetings tiers, the firm’s Meetings plan and this month’s minutes.

The fields are as shown above.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Cancel the subscription

POST/api/v1/billing/subscription/cancel

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

Monthly plans: one month’s notice. Annual plans: at renewal (no refund).

Responses

200 OK, application/json

Body: object (Subscription).

The fields are as shown above.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Keep a subscription that is set to cancel

POST/api/v1/billing/subscription/resume

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

Responses

200 OK, application/json

Body: object (Subscription).

The fields are as shown above.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

List billable engagements (started and credited) in a period (default: this month)

GET/api/v1/billing/usage

Scopes
settings:admin
Role
Firm admin

Parameters

Parameters for GET /api/v1/billing/usage
NameInTypeDescription
fromquerystring (date)
toquerystring (date)

Responses

200 OK, application/json

Body: object (BillingUsage).

200 OK response for GET /api/v1/billing/usage
FieldTypeDescription
fromrequiredstring (date-time)
torequiredstring (date-time)
summaryrequiredobject (BillingPeriodSummary)
summary.​startedrequiredinteger
summary.​creditedrequiredinteger
summary.​freerequiredinteger
summary.​billablerequiredinteger
summary.​estimaterequiredobject (BillingEstimate)
summary.​estimate.​totalPencerequiredinteger

Integer pence (GBP).

summary.​estimate.​linesrequiredarray of TierLine
summary.​estimate.​lines[].​fromrequiredinteger
summary.​estimate.​lines[].​torequiredinteger
summary.​estimate.​lines[].​countrequiredinteger
summary.​estimate.​lines[].​unitPencerequiredinteger

Integer pence (GBP).

summary.​estimate.​lines[].​amountPencerequiredinteger

Integer pence (GBP).

eventsrequiredarray of BillableEvent
events[].​idrequiredstring (uuid)
events[].​kindrequiredstring (BillableKind)

One of: started, credit

events[].​engagementIdrequiredstring (uuid)
events[].​clientIdrequiredstring (uuid)
events[].​clientNamerequiredstring
events[].​periodEndrequiredstring (date)

example "2026-03-31"

events[].​sourcerequiredstring (BillableSource)

One of: web, api, mcp, bulk

events[].​startedByrequiredstring (uuid)nullable
events[].​freerequiredboolean

One of the trial’s free engagements.

events[].​atrequiredstring (date-time)
events[].​reportableAtrequiredstring (date-time)nullable

When the cancellation window closes and it is reported to Stripe.

events[].​reportedAtrequiredstring (date-time)nullable

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

List invoices (Stripe-hosted)

GET/api/v1/billing/invoices

Scopes
settings:admin
Role
Firm admin

Responses

200 OK, application/json

Body: array of Invoice.

200 OK response for GET /api/v1/billing/invoices
FieldTypeDescription
[].​idrequiredstring (uuid)
[].​stripeInvoiceIdrequiredstring
[].​numberrequiredstringnullable
[].​statusrequiredstring
[].​amountDuePencerequiredinteger

Integer pence (GBP).

[].​amountPaidPencerequiredinteger

Integer pence (GBP).

[].​currencyrequiredstring
[].​hostedInvoiceUrlrequiredstringnullable
[].​invoicePdfrequiredstringnullable
[].​periodStartrequiredstring (date-time)nullable
[].​periodEndrequiredstring (date-time)nullable
[].​createdAtrequiredstring (date-time)

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Set billing details (contact, VAT number) and create the Stripe customer

POST/api/v1/billing/setup

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

Choose a plan with POST /billing/subscription; add a payment method in the Customer Portal.

Request body

Required. application/json: object (BillingSetup).

Request body for POST /api/v1/billing/setup
FieldTypeDescription
billingEmailstring (email)
vatNumberstring

example "GB123456789"

Responses

200 OK, application/json

Body: object (BillingAccount).

The fields are as shown above.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Open the Stripe Customer Portal (payment method, billing details, invoices)

POST/api/v1/billing/portal

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

Responses

200 OK, application/json

Body: object (PortalSession).

200 OK response for POST /api/v1/billing/portal
FieldTypeDescription
urlrequiredstring (uri)

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Check whether new engagements can start

GET/api/v1/billing/start-status

Scopes
engagements:write

The same gate as starting (402 when blocked): trial’s free engagements used or the trial over without a plan, or an invoice unpaid for 14 days. Viewing and exports are never blocked.

Responses

200 OK, application/json

Body: object (EngagementStartStatus).

Whether the firm can start engagements now. Readable by anyone who starts engagements; no prices, plan or invoices.

200 OK response for GET /api/v1/billing/start-status
FieldTypeDescription
canStartrequiredboolean

False when starting an engagement would fail with 402.

reasonrequiredstring (StartBlockReason)nullable

Why starting is blocked: an invoice unpaid for 14 days, the trial’s free engagements used, or the trial over without a plan. Null when it isn’t.

One of: dunning, plan_required, trial_ended

messagerequiredstringnullable

The same message a blocked start returns with its 402.

startsLeftrequiredintegernullable

How many more engagements can start before the gate closes (the trial’s free ones left); null when there is no limit.

at least 0

allowanceobject (StartAllowance)nullable

The plan year’s engagement allowance, as counts: how many have been used and how many the plan includes. Null on the trial, an Enterprise plan or no plan. Going over never stops work.

allowance.​usedrequiredinteger

at least 0

allowance.​totalrequiredinteger

at least 0

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Get the business’s Tolvi Books plan and the tiers

GET/api/v1/books/billing

Scopes
books:admin

How Tolvi Books is paid for (a trial, the business, or its accountant), the tier the business needs, the tiers with monthly and annual prices, and this month’s AI fair use. Owners and admins.

Responses

200 OK, application/json

Body: object (BooksBilling).

A business’s Tolvi Books plan, how it is paid for, and the tiers.

200 OK response for GET /api/v1/books/billing
FieldTypeDescription
catalogueVersionrequiredstring
priceStatusrequiredstring (BooksPriceStatus)

placeholder: prices still to be confirmed.

One of: placeholder, draft, confirmed

vatRegisteredrequiredboolean

Tolvi charges VAT on top of these prices.

annualDiscountBpsrequiredinteger

at least 0

trialDaysrequiredinteger

at least 0

plansrequiredarray of BooksPlan
plans[].​idrequiredstring (BooksPlanId)

One of: books_sole_trader, books_limited_company, books_vat_registered

plans[].​namerequiredstring
plans[].​whorequiredstring

Who the plan is for, in plain English.

plans[].​monthlyPencerequiredinteger

Integer pence (GBP).

at least 0

plans[].​annualPencerequiredinteger

Integer pence (GBP).

12 × monthly less the annual discount, in whole pounds.

at least 0

plans[].​wholesaleMonthlyPencerequiredinteger

Integer pence (GBP).

What a practice pays per client a month.

at least 0

plans[].​aiFairUsePerMonthrequiredinteger

AI suggestions a month within fair use. Past it, nothing stops and nothing is charged.

at least 0

plans[].​vatReturnsrequiredboolean

MTD VAT returns are included.

plans[].​includesrequiredarray of string
requiredPlanIdrequiredstring (BooksPlanId)

The tier this business needs (from its type and VAT registration); it may choose a higher one.

One of: books_sole_trader, books_limited_company, books_vat_registered

statusrequiredstring (FirmProductStatus)

suspended: read-only (an ended trial, or no plan). Reading and exporting are never blocked.

One of: active, trial, suspended

paidByrequiredstring (BooksPaidBy)

One of: business, practice, trial, included, none

practicerequiredobject (BooksPayingPractice)nullable
practice.​linkIdrequiredstring (uuid)
practice.​firmNamerequiredstring
planIdrequiredstring (BooksPlanId)nullable

One of: books_sole_trader, books_limited_company, books_vat_registered

planNamerequiredstringnullable
intervalrequiredstring (PlanInterval)nullable

One of: month, year

trialEndsAtrequiredstring (date-time)nullable
currentPeriodEndsAtrequiredstring (date-time)nullable
cancelAtrequiredstring (date-time)nullable
scheduledChangerequiredobject (BooksScheduledChange)nullable
scheduledChange.​planIdrequiredstring (BooksPlanId)nullable

Null: Tolvi Books ends.

One of: books_sole_trader, books_limited_company, books_vat_registered

scheduledChange.​intervalrequiredstring (PlanInterval)nullable

Moves to this billing period; null keeps the current one.

One of: month, year

scheduledChange.​effectiveAtrequiredstring (date-time)nullable
pendingCheckoutUrlrequiredstring (uri)nullable

A Checkout started but not finished: send the browser here.

fairUserequiredobject (BooksFairUse)

AI suggestions this calendar month (UTC) against the fair-use allowance.

fairUse.​monthrequiredstring

example "2026-10"

fairUse.​allowancerequiredinteger

at least 0

fairUse.​usedrequiredinteger

at least 0

fairUse.​remainingrequiredinteger

at least 0

fairUse.​overrequiredboolean
endedAtrequiredstring (date-time)nullable

When the plan or trial ended. Set while read-only; cleared on choosing a plan.

dataDeletesOnrequiredstring (date-time)nullable

When the books are due to be deleted: 6 years after endedAt.

dataDeletedAtrequiredstring (date-time)nullable

When the books were deleted, 6 years after the plan ended.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Choose, change or cancel the business’s Tolvi Books plan

PUT/api/v1/books/billing/plan

Scopes
books:admin
Access
A signed-in Tolvi session only, never an API token.

Without a plan: Stripe Checkout (interval month or year; see pendingCheckoutUrl), and Tolvi Books is paid for once the first invoice is. With one: upgrades apply at once, prorated, once paid; downgrades and cancelling (planId null) at the end of the billing period. The current plan with another interval switches how it is billed: to year at once, prorated, once paid; to month at the end of the billing period. The tier must be at least requiredPlanId. Refused (409) while the business’s accountant pays. Signed-in owners and admins only.

Request body

Required. application/json: object (ChangeBooksPlan).

Request body for PUT /api/v1/books/billing/plan
FieldTypeDescription
planIdrequiredstring (BooksPlanId)nullable

Null cancels at the end of the billing period.

One of: books_sole_trader, books_limited_company, books_vat_registered

intervalstring (PlanInterval)

Buying a first plan (default month), or moving the current plan: to year applies now, prorated; to month at the end of the billing period.

One of: month, year

Responses

200 OK, application/json

Body: object (BooksBilling).

A business’s Tolvi Books plan, how it is paid for, and the tiers.

The fields are as shown above.

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Open the Stripe Customer Portal for the business

POST/api/v1/books/billing/portal

Scopes
books:admin
Access
A signed-in Tolvi session only, never an API token.

Payment method, billing details and invoices. Signed-in owners and admins only.

Responses

200 OK, application/json

Body: object (BooksPortalSession).

200 OK response for POST /api/v1/books/billing/portal
FieldTypeDescription
urlrequiredstring (uri)

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

List the firm’s Tolvi Books clients and whose Books it pays for

GET/api/v1/practice/books/billing

Scopes
settings:admin
Role
Firm admin

Every business with a live link, the tier it needs, the wholesale price and whether the firm pays.

Responses

200 OK, application/json

Body: object (PracticeBooksBilling).

The firm’s linked clients and whose Tolvi Books it pays for, at the wholesale price.

200 OK response for GET /api/v1/practice/books/billing
FieldTypeDescription
catalogueVersionrequiredstring
priceStatusrequiredstring (BooksPriceStatus)

placeholder: prices still to be confirmed.

One of: placeholder, draft, confirmed

vatRegisteredrequiredboolean
consentVersionrequiredstring
plansrequiredarray of PracticeBooksPlan
plans[].​idrequiredstring (BooksPlanId)

One of: books_sole_trader, books_limited_company, books_vat_registered

plans[].​namerequiredstring
plans[].​whorequiredstring
plans[].​wholesaleMonthlyPencerequiredinteger

Integer pence (GBP).

at least 0

subscribedrequiredboolean

The firm has a Tolvi subscription to add clients to. Without one, paying for a client starts a Stripe Checkout for Tolvi Books alone.

pendingCheckoutUrlrequiredstring (uri)nullable

A Checkout for clients’ Tolvi Books started but not finished: send the browser here.

monthlyTotalPencerequiredinteger

Integer pence (GBP).

at least 0

clientsrequiredarray of PracticeBooksClient
clients[].​linkIdrequiredstring (uuid)
clients[].​businessIdrequiredstring (uuid)
clients[].​businessNamerequiredstring
clients[].​clientPrefersrequiredstring (LinkBilledBy)

Who the business said should pay, on its link.

One of: business, firm

clients[].​planIdrequiredstring (BooksPlanId)nullable

The tier the business needs.

One of: books_sole_trader, books_limited_company, books_vat_registered

clients[].​planNamerequiredstringnullable
clients[].​wholesaleMonthlyPencerequiredintegernullable

Integer pence (GBP).

at least 0

clients[].​booksStatusrequiredstring (FirmProductStatus)nullable

Null: the firm doesn’t have Meetings.

One of: active, trial, suspended

clients[].​trialEndsAtrequiredstring (date-time)nullable
clients[].​paysItselfrequiredboolean

The business pays for its own plan.

clients[].​consentTextrequiredstringnullable

What a firm admin agrees to before paying for this client.

clients[].​billingrequiredobject (PracticeBooksClientBilling)nullable
clients[].​billing.​statusrequiredstring (PracticeBooksBillingStatus)

pending: waiting for the prorated invoice to be paid.

One of: pending, active

clients[].​billing.​sincerequiredstring (date-time)
clients[].​billing.​paymentUrlrequiredstring (uri)nullable

Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).

Pay for a client’s Tolvi Books

POST/api/v1/practice/books/billing/clients/{linkId}

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.
Retries
Send an Idempotency-Key to make retries safe.

Adds the client to the firm’s Tolvi invoice at the wholesale price for the tier it needs, prorated, from today (agree: true records the firm admin’s agreement to the client’s consentText). Paid for once that invoice is paid. A firm with no Tolvi subscription gets a Stripe Checkout for Tolvi Books alone (see pendingCheckoutUrl); the client starts once its first invoice is paid. Needs a live link; refused (409) if the business already pays for itself, or while another Checkout is unfinished.

Parameters

Parameters for POST /api/v1/practice/books/billing/clients/{linkId}
NameInTypeDescription
linkIdrequiredpathstring (uuid)
Idempotency-Keyheaderstring

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 (PayForClientBooks).

Request body for POST /api/v1/practice/books/billing/clients/{linkId}
FieldTypeDescription
agreerequiredboolean

Must be true: the firm admin agrees to the client’s consentText.

Responses

200 OK, application/json

Body: object (PracticeBooksBilling).

The firm’s linked clients and whose Tolvi Books it pays for, at the wholesale price.

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).

Stop paying for a client’s Tolvi Books

POST/api/v1/practice/books/billing/clients/{linkId}/stop

Scopes
settings:admin
Role
Firm admin
Access
A signed-in Tolvi session only, never an API token.

Takes the client off the firm’s invoice now (credited, prorated). The business keeps its books and gets a grace period before it must choose a plan of its own.

Parameters

Parameters for POST /api/v1/practice/books/billing/clients/{linkId}/stop
NameInTypeDescription
linkIdrequiredpathstring (uuid)

Request body

Optional. application/json: object (StopPayingForClientBooks).

Request body for POST /api/v1/practice/books/billing/clients/{linkId}/stop
FieldTypeDescription
reasonstring

up to 500 characters

Responses

200 OK, application/json

Body: object (PracticeBooksBilling).

The firm’s linked clients and whose Tolvi Books it pays for, at the wholesale price.

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).