Self Assessment
48 operations in the Tolvi API, version 1. Paths are relative to https://api.tolvi.co.uk. Every amount is integer pence.
List returns
GET/api/v1/self-assessment/returns
- Scopes
self_assessment:read
Every client’s return, with its status and how long is left. Filter by client, tax year or status. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
status | query | string | |
taxYearEnd | query | integer | |
clientId | query | string (uuid) |
Responses
200 OK, application/json
Body: object (SaReturnList).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of SaReturnRow | |
items[].idrequired | string (uuid) | |
items[].clientIdrequired | string (uuid) | |
items[].clientNamerequired | string | |
items[].taxYearEndrequired | integer | |
items[].returnTyperequired | string (SaReturnType) | One of: |
items[].taxYearrequired | string | example "2025/26" |
items[].statusrequired | string (SaReturnStatus) | One of: |
items[].dueDaterequired | string (date) | example "2026-03-31" |
items[].daysLeftrequired | integer | Days to the online deadline; negative when overdue. |
items[].openReviewPointsrequired | integer | Open review points. |
items[].updatedAtrequired | string (date-time) | |
taxYearEndsrequired | array of integer | Tax years Tolvi can prepare, by the year they end. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Start a return
POST/api/v1/self-assessment/returns
- Scopes
self_assessment:write- Role
- Preparer or above
- Retries
- Send an
Idempotency-Keyto make retries safe.
Preparers and above. One of each form per client and tax year: an SA100, an SA800 or an SA900. Last year’s details carry forward, and on an SA900 the tax pool.
Needs the Preparer role or above. Part of the self_assessment 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 (CreateSaReturnRequest).
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
taxYearEndrequired | integer | The year the tax year ends: 2026 is 2025/26. Tolvi can prepare 2025/26 onwards. example 2026 |
returnType | string (SaReturnType) | SA100 unless said otherwise. An SA800 needs a partnership or LLP client. One of: |
Responses
201 Created, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
clientIdrequired | string (uuid) | |
clientNamerequired | string | |
taxYearEndrequired | integer | |
returnTyperequired | string (SaReturnType) | One of: |
taxYearrequired | string | example "2025/26" |
statusrequired | string (SaReturnStatus) | One of: |
dueDaterequired | string (date) | example "2026-03-31" |
daysLeftrequired | integer | Days to the online deadline; negative when overdue. |
openReviewPointsrequired | integer | Open review points. |
updatedAtrequired | string (date-time) | |
importedLastYearrequired | object (SaPriorYearFigures)nullable | Last year’s figures brought in from other software, if any. For comparison: on no return and in no calculation. |
importedLastYear.taxYearEndrequired | integer | |
importedLastYear.figuresrequired | object | Pence, by field. |
partnersrequired | array of SaReturnPartner | SA800 only: who shares the statement. |
partners[].namerequired | string | As on the partnership statement. |
partners[].utrrequired | string | Ten digits. |
partners[].shareBpsrequired | integer | Profit share in basis points. Across the partners they add up to 10000. |
partners[].clientId | string (uuid)nullable | Their own client record at this firm: their SA100 is offered their SA104 as a suggestion. |
partners[].dateAppointed | string (date)nullable | example "2026-03-31" |
partners[].dateCeased | string (date)nullable | example "2026-03-31" |
trustKindrequired | stringnullable | SA900 only: what the return says it is, in words. |
pagesrequired | object | Box values by page: { sa100: { INC1: 12000 }, sa102: [{ EMP1: 4000000 }] }. Money is integer pence. Sensitive boxes aren’t here. |
sourcesrequired | object | Where figures came from, keyed sa102.0.EMP1. For AI Mode: { source: "ai", evidence: [{ kind, label, quote, value, documentId, documentPage }], reviewedAt }. |
masksrequired | object | Masked National Insurance number, date of birth and bank details. |
otherPaymentsrequired | object | { paymentsOnAccountMade, otherPaymentsMade } in pence. |
prepModerequired | string (SaPrepMode)nullable | How it’s being prepared, once someone has chosen. One of: |
aiFiguresToConfirmrequired | integer | Figures AI filled that a person hasn’t checked. It can’t go for review until this is nil. |
calculationrequired | object | { c, cal, sa302, unsupported, filable }: HMRC’s calculation for the pages Tolvi covers. |
problemsrequired | array of SaProblem | What HMRC’s rules would refuse. |
problems[].pagerequired | string | example "SA102" |
problems[].boxrequired | string | example "EMP4" |
problems[].messagerequired | string | |
returnHashrequired | string | Send this back when approving: it fingerprints the figures. |
utrrequired | stringnullable | |
approvedByNamerequired | stringnullable | |
approvedAtrequired | string (date-time)nullable | |
clientApprovedOnrequired | string (date)nullable | example "2026-03-31" |
clientApprovalCurrentrequired | boolean | The client approved these figures, not earlier ones. |
approverRolerequired | string (ApproverRole) | Who may approve in this firm: partners only, or managers and partners. One of: |
canApproverequired | boolean | |
cannotApproveReasonrequired | stringnullable | |
canSubmitrequired | boolean | |
cannotSubmitReasonrequired | stringnullable | |
filingEnabledrequired | boolean | Whether filing is switched on: off until HMRC has approved Tolvi. |
filingModerequired | string (SaFilingMode) | One of: |
declarationrequired | object | { version, text }: the declaration to accept before filing. |
reviewPointsrequired | array of SaReviewPoint | |
reviewPoints[].idrequired | string (uuid) | |
reviewPoints[].boxKeyrequired | stringnullable | |
reviewPoints[].textrequired | string | |
reviewPoints[].statusrequired | string (SaReviewPointStatus) | One of: |
reviewPoints[].raisedByNamerequired | stringnullable | |
reviewPoints[].createdAtrequired | string (date-time) | |
eventsrequired | array of SaEvent | |
events[].idrequired | string (uuid) | |
events[].kindrequired | string | |
events[].actorNamerequired | stringnullable | |
events[].noterequired | stringnullable | |
events[].createdAtrequired | string (date-time) | |
submissionsrequired | array of SaSubmission | |
submissions[].idrequired | string (uuid) | |
submissions[].moderequired | string (SaSubmissionMode) | test and test_in_live never reach a taxpayer’s record. One of: |
submissions[].statusrequired | string (SaSubmissionStatus) | One of: |
submissions[].correlationIdrequired | stringnullable | |
submissions[].irmarkrequired | string | |
submissions[].errorsrequired | array of objectnullable | HMRC’s errors: { number, text, location }. |
submissions[].messagerequired | stringnullable | What this means, in plain words. |
submissions[].receiptAtrequired | string (date-time)nullable | |
submissions[].submittedByNamerequired | stringnullable | |
submissions[].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 return
GET/api/v1/self-assessment/returns/{id}
- Scopes
self_assessment:read
The boxes and where each came from, HMRC’s calculation for them, what HMRC’s rules would refuse, review points and history. The National Insurance number, date of birth and bank details are only ever masked. Part of the self_assessment 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 (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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 return
PATCH/api/v1/self-assessment/returns/{id}
- Scopes
self_assessment:write- Role
- Preparer or above
Preparers and above. Changing an approved or reviewed return takes it back to draft. Refused once it’s with HMRC.
Needs the Preparer role or above. Part of the self_assessment 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 (UpdateSaReturnRequest).
Send only what changes. Changing an approved return takes it back to draft.
| Field | Type | Description |
|---|---|---|
changes | array of object | { page, instance?, box, value, source? }. Box is HMRC’s mnemonic, such as INC1; money is integer pence; null clears. |
addPages | array of string | Pages to add: sa101, sa102, sa102m, sa103f, sa103s, sa103l, sa104f, sa104s, sa105, sa106, sa107, sa108, sa109. |
removePages | array of object | { page, instance? } to remove. |
otherPayments | object | { paymentsOnAccountMade, otherPaymentsMade } in pence: payments towards this year, for the balance due. |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get what a return needs
GET/api/v1/self-assessment/returns/{id}/plan
- Scopes
self_assessment:read
The questions that decide which pages and boxes a return needs, the answers so far, and the steps they lead to. Used by Simple Step and AI Mode alike. Part of the self_assessment 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 (SaPlan).
Which pages and steps a return needs, from the answers so far. Nothing counts as a no until it’s answered.
| Field | Type | Description |
|---|---|---|
questionnaireVersionrequired | string | |
questionsrequired | array of SaQuestion | The questions that apply, given the answers. |
questions[].idrequired | string | |
questions[].textrequired | string | |
questions[].help | string | |
questions[].kindrequired | string (SaQuestionKind) | One of: |
questions[].section | string | The SA100 section a yes opens. |
questions[].outOfScope | object | { form, title }: a page Tolvi can’t prepare yet, if the answer is yes. |
answersrequired | object | Answers so far. |
unansweredrequired | array of string | |
completerequired | boolean | |
pagesNeededrequired | object | { sa102: 2, sa103s: 0, ... }. |
outOfScoperequired | array of object | { form, title }: pages the answers call for that can’t be filed from Tolvi. |
stepsrequired | array of SaPlanStep | |
steps[].keyrequired | string | example "sa102.0" |
steps[].titlerequired | string | |
steps[].pagerequired | string | example "sa102" |
steps[].instancerequired | integernullable | |
steps[].boxesrequired | array of stringnullable | The boxes on this step. Null means every box on the page. |
extraPagesrequired | array of object | { page, instance }: pages with figures the answers no longer call for. A person decides. |
prepModerequired | string (SaPrepMode)nullable | How it’s being prepared, once someone has chosen. One of: |
suggested | object | { questionId: { value, why } }: answers Tolvi can suggest from last year, the client’s record and what HMRC holds. None counts until a person accepts it. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Answer what a return needs
PUT/api/v1/self-assessment/returns/{id}/plan
- Scopes
self_assessment:write- Role
- Preparer or above
Preparers and above. Saves answers and brings the pages into line. Pages with figures are never removed: they’re listed in extraPages for a person to decide.
Needs the Preparer role or above. Part of the self_assessment 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 (SaveSaAnswersRequest).
Answers merge over what’s there. Pages are added to match, and empty pages no longer needed are removed. Pages with figures are never removed.
| Field | Type | Description |
|---|---|---|
answersrequired | object | { questionId: true, otherId: 2 }. |
prepMode | string (SaPrepMode) | How it’s being prepared, once someone has chosen. One of: |
Responses
200 OK, application/json
Body: object (SaPlan).
Which pages and steps a return needs, from the answers so far. Nothing counts as a no until it’s answered.
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).
Download the full return
GET/api/v1/self-assessment/returns/{id}/pdf
- Scopes
self_assessment:read
Every page of the return in the style of HMRC’s forms, then the calculation, as a PDF: to send the client for their approval, or to file another way until Tolvi can. Sensitive boxes appear masked. Part of the self_assessment 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
A PDF.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Download the SA302
GET/api/v1/self-assessment/returns/{id}/sa302
- Scopes
self_assessment:read
The tax calculation alone, in the order of HMRC’s SA302, as a PDF. Prepared from the return’s figures, and says how far the return has got; not issued by HMRC. Part of the self_assessment 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
A PDF.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Set the partners on an SA800
PUT/api/v1/self-assessment/returns/{id}/partners
- Scopes
self_assessment:write- Role
- Preparer or above
Who shares the partnership statement and how. The statement’s figures are allocated to them, and a partner with a client record here is offered their SA104 as a suggestion on their own SA100. Changing an approved return takes it back to draft.
Needs the Preparer role or above. Part of the self_assessment 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 (SetSaPartnersRequest).
Replaces the partners and allocates the statement to them. A share a person typed over is replaced too. Changing an approved return takes it back to draft.
| Field | Type | Description |
|---|---|---|
partnersrequired | array of SaReturnPartner | |
partners[].namerequired | string | As on the partnership statement. |
partners[].utrrequired | string | Ten digits. |
partners[].shareBpsrequired | integer | Profit share in basis points. Across the partners they add up to 10000. |
partners[].clientId | string (uuid)nullable | Their own client record at this firm: their SA100 is offered their SA104 as a suggestion. |
partners[].dateAppointed | string (date)nullable | example "2026-03-31" |
partners[].dateCeased | string (date)nullable | example "2026-03-31" |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Download an R185
POST/api/v1/self-assessment/returns/{id}/r185
- Scopes
self_assessment:read
A statement for a beneficiary of a trust or estate, worked from the SA900, as a PDF. A person checks and signs it; it isn’t filed and isn’t kept. Trust management expenses aren’t taken off: send your own figures in overrides. Not issued by HMRC. Part of the self_assessment 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 (MakeR185Request).
A statement for a beneficiary, worked from the SA900. Not filed. A person checks and signs it.
| Field | Type | Description |
|---|---|---|
kindrequired | string (R185Kind) | One of: |
beneficiaryrequired | string | |
shareBps | integer | Their share of the income in basis points. Needed unless discretionary. |
paymentIndex | integer | Which row of box 14, from 0. Needed for a discretionary statement. |
overrides | object | A person’s own figures in pence, by the form’s box: { "3": 1000, "3.tax": 250 }. |
deceasedName | string | |
dateOfDeath | string (date) | example "2026-03-31" |
Responses
200 OK
A PDF.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Bring in section T
POST/api/v1/self-assessment/returns/{id}/import/working-papers
- Scopes
self_assessment:write- Role
- Preparer or above
Fills the SA103 from a sole trader’s section T in Working Papers. Answers such as dates stay for a person to give.
Needs the Preparer role or above. Part of the self_assessment 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 (ImportSaFromWorkingPapersRequest).
| Field | Type | Description |
|---|---|---|
engagementIdrequired | string (uuid) | A sole trader engagement of this client, with section T worked. |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
See what HMRC holds
GET/api/v1/self-assessment/returns/{id}/hmrc-data
- Scopes
self_assessment:read
As last fetched: figures you can apply, and the Self Assessment account. Part of the self_assessment 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 (SaHmrcData).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of SaHmrcDataItem | |
items[].sourcerequired | string (SaHmrcDataSource) | One of: |
items[].outcomerequired | string (SaHmrcDataOutcome) | One of: |
items[].fetchedAtrequired | string (date-time) | |
suggestionsrequired | array of SaHmrcSuggestion | |
suggestions[].pagerequired | string | |
suggestions[].instancerequired | integernullable | Which SA102, when the return already has a page for this employer. |
suggestions[].employerPayeReferencerequired | stringnullable | |
suggestions[].boxrequired | string | |
suggestions[].labelrequired | string | |
suggestions[].sourcerequired | string | |
suggestions[].valuerequired | object | HMRC’s figure: pence for money. |
suggestions[].currentrequired | objectnullable | The figure on the return now, or null. |
accountrequired | object (SaHmrcAccount)nullable | From View Self Assessment Account, in pence. |
account.totalBalancePencerequired | integernullable | Integer pence (GBP). |
account.totalOverduePencerequired | integernullable | Integer pence (GBP). |
account.totalPayablePencerequired | integernullable | Integer pence (GBP). |
account.totalCreditPencerequired | integernullable | Integer pence (GBP). |
account.earliestPayableDueDaterequired | string (date)nullable | example "2026-03-31" |
noterequired | string | What HMRC doesn’t give, so nobody waits for it. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Ask HMRC what it holds
POST/api/v1/self-assessment/returns/{id}/hmrc-data/refresh
- Scopes
self_assessment:write- Role
- Preparer or above
Preparers and above, with a connected HMRC account authorised for this client.
Needs the Preparer role or above. Part of the self_assessment 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 (RefreshSaHmrcDataRequest).
| Field | Type | Description |
|---|---|---|
agentAccountIdrequired | string (uuid) | |
clientFactsrequired | object | The browser’s facts for HMRC’s fraud prevention headers. |
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Put HMRC’s figures on the return
POST/api/v1/self-assessment/returns/{id}/hmrc-data/apply
- Scopes
self_assessment:write- Role
- Preparer or above
The figures you choose. An SA102 is added for an employer the return doesn’t have.
Needs the Preparer role or above. Part of the self_assessment 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 (ApplySaHmrcDataRequest).
| Field | Type | Description |
|---|---|---|
selectionsrequired | array of SaHmrcSelection | The figures from what HMRC holds to put on the return. |
selections[].boxrequired | string | example "EMP1" |
selections[].employerPayeReference | stringnullable | For an SA102: the employer. |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Send for review
POST/api/v1/self-assessment/returns/{id}/send-for-review
- Scopes
self_assessment:write- Role
- Preparer or above
Preparers and above, from draft.
Needs the Preparer role or above. Part of the self_assessment 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 (SaNoteRequest).
| Field | Type | Description |
|---|---|---|
note | string | up to 2000 characters |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Return to draft
POST/api/v1/self-assessment/returns/{id}/return-to-draft
- Scopes
review:write- Role
- Reviewer or above
Reviewers and above. An approval is lost.
Needs the Reviewer role or above. Part of the self_assessment 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 (SaNoteRequest).
| Field | Type | Description |
|---|---|---|
note | string | up to 2000 characters |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Raise a review point
POST/api/v1/self-assessment/returns/{id}/review-points
- Scopes
review:write- Role
- Reviewer or above
Reviewers and above. Open points stop a return being approved.
Needs the Reviewer role or above. Part of the self_assessment 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 (RaiseSaReviewPointRequest).
| Field | Type | Description |
|---|---|---|
textrequired | string | 1 to 2000 characters |
boxKey | string | The box it’s about, such as sa102.0.EMP1. |
Responses
201 Created, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Clear a review point
POST/api/v1/self-assessment/returns/{id}/review-points/{pointId}/clear
- Scopes
review:write- Role
- Reviewer or above
Reviewers and above.
Needs the Reviewer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
pointIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Approve a return
POST/api/v1/self-assessment/returns/{id}/approve
- Scopes
review:write- Role
- Manager or above
- Access
- A signed-in Tolvi session only, never an API token.
A partner, signed in, or a manager where the firm allows it (403 otherwise). Refused with open review points, with anything HMRC’s rules would refuse, or if the figures moved since you reviewed them. Never available to connected assistants.
Needs the Manager role or above. Part of the self_assessment 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 (ApproveSaReturnRequest).
| Field | Type | Description |
|---|---|---|
returnHashrequired | string | The hash from the return you reviewed: refused if the figures have moved since. |
note | string | up to 2000 characters |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Record the client’s approval
POST/api/v1/self-assessment/returns/{id}/client-approval
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
HMRC requires the client to confirm in writing the copy they were sent. Applies only to these figures. Never available to connected assistants.
Needs the Preparer role or above. Part of the self_assessment 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 (RecordSaClientApprovalRequest).
HMRC requires the client to confirm in writing that the return they were sent is correct and complete, before an agent files it.
| Field | Type | Description |
|---|---|---|
approvedOnrequired | string (date) | example "2026-03-31" |
note | string | How they confirmed, such as an email. up to 2000 characters |
returnHashrequired | string |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
File with HMRC
POST/api/v1/self-assessment/returns/{id}/submit
- Scopes
self_assessment:write- Role
- Manager or above
- Access
- A signed-in Tolvi session only, never an API token.
- Retries
- Send an
Idempotency-Keyto make retries safe.
A manager or partner, signed in with a second factor, once these figures are approved and the client has confirmed them. Answers 503 until filing is switched on, once HMRC has approved Tolvi. Never available to connected assistants.
Needs the Manager role or above. Part of the self_assessment 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 (SubmitSaReturnRequest).
| Field | Type | Description |
|---|---|---|
returnHashrequired | string | |
agentAccountIdrequired | string (uuid) | |
declarationrequired | object | { accepted: true, version }: the agent’s declaration HMRC requires. |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
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).
Ask HMRC for its answer
POST/api/v1/self-assessment/returns/{id}/submissions/{submissionId}/poll
- Scopes
self_assessment:read
While HMRC is checking a return. Tolvi also asks by itself. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
submissionIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Get AI Mode on a return
GET/api/v1/self-assessment/returns/{id}/ai
- Scopes
self_assessment:read
The conversation, the documents, the plan, and about what the next turn would cost. Not available to connected assistants. Part of the self_assessment 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 (SaAiState).
AI Mode on a return: the conversation, the documents, and what it would cost to carry on.
| Field | Type | Description |
|---|---|---|
availablerequired | boolean | Whether the firm has AI Mode on. |
unavailableReasonrequired | stringnullable | |
messagesrequired | array of SaAiMessage | |
messages[].idrequired | string (uuid) | |
messages[].rolerequired | string (SaAiMessageRole) | One of: |
messages[].textrequired | string | |
messages[].outcomerequired | objectnullable | On an assistant’s turn: { applied, cleared, refused, answers, stillNeeded, tokens }. |
messages[].createdAtrequired | string (date-time) | |
documentsrequired | array of SaDocument | |
documents[].idrequired | string (uuid) | |
documents[].fileNamerequired | string | |
documents[].contentTyperequired | string | |
documents[].sizeBytesrequired | integer | |
documents[].statusrequired | string (SaDocumentStatus) | One of: |
documents[].rejectedReasonrequired | stringnullable | |
documents[].readingStatusrequired | string (SaDocumentReadingStatus) | One of: |
documents[].readingrequired | objectnullable | { documentType, taxYearShown, readings, warnings }. |
documents[].createdAtrequired | string (date-time) | |
planrequired | object (SaPlan) | Which pages and steps a return needs, from the answers so far. Nothing counts as a no until it’s answered. |
plan.questionnaireVersionrequired | string | |
plan.questionsrequired | array of SaQuestion | The questions that apply, given the answers. |
plan.questions[].idrequired | string | |
plan.questions[].textrequired | string | |
plan.questions[].help | string | |
plan.questions[].kindrequired | string (SaQuestionKind) | One of: |
plan.questions[].section | string | The SA100 section a yes opens. |
plan.questions[].outOfScope | object | { form, title }: a page Tolvi can’t prepare yet, if the answer is yes. |
plan.answersrequired | object | Answers so far. |
plan.unansweredrequired | array of string | |
plan.completerequired | boolean | |
plan.pagesNeededrequired | object | { sa102: 2, sa103s: 0, ... }. |
plan.outOfScoperequired | array of object | { form, title }: pages the answers call for that can’t be filed from Tolvi. |
plan.stepsrequired | array of SaPlanStep | |
plan.steps[].keyrequired | string | example "sa102.0" |
plan.steps[].titlerequired | string | |
plan.steps[].pagerequired | string | example "sa102" |
plan.steps[].instancerequired | integernullable | |
plan.steps[].boxesrequired | array of stringnullable | The boxes on this step. Null means every box on the page. |
plan.extraPagesrequired | array of object | { page, instance }: pages with figures the answers no longer call for. A person decides. |
plan.prepModerequired | string (SaPrepMode)nullable | How it’s being prepared, once someone has chosen. One of: |
plan.suggested | object | { questionId: { value, why } }: answers Tolvi can suggest from last year, the client’s record and what HMRC holds. None counts until a person accepts it. |
phaserequired | string (SaAiPhase) | What the next turn does: finds out what’s needed, fills the boxes, or acts on a request. One of: |
estimaterequired | object (SaAiEstimate)nullable | |
estimate.tokensrequired | integer | Tolvi AI tokens, about. |
estimate.affordablerequired | boolean | |
estimate.reasonrequired | stringnullable |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Tell or ask AI Mode
POST/api/v1/self-assessment/returns/{id}/ai/messages
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
Preparers and above, on a draft. Spends the firm’s Tolvi AI tokens. Any figure it changes is read by Tolvi from the evidence it cites, and goes back to needing a person’s check. Refused figures are returned with the reason.
Needs the Preparer role or above. Part of the self_assessment 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 (SendSaAiMessageRequest).
| Field | Type | Description |
|---|---|---|
textrequired | string | What you want to tell or ask. National Insurance numbers, UTRs and bank details are removed before it’s stored or sent. 1 to 4000 characters |
Responses
200 OK, application/json
Body: object (SaAiTurn).
One turn of AI Mode. Every figure was read from the evidence it cites by Tolvi, not the model.
| Field | Type | Description |
|---|---|---|
availablerequired | boolean | Whether the firm has AI Mode on. |
unavailableReasonrequired | stringnullable | |
messagesrequired | array of SaAiMessage | |
messages[].idrequired | string (uuid) | |
messages[].rolerequired | string (SaAiMessageRole) | One of: |
messages[].textrequired | string | |
messages[].outcomerequired | objectnullable | On an assistant’s turn: { applied, cleared, refused, answers, stillNeeded, tokens }. |
messages[].createdAtrequired | string (date-time) | |
documentsrequired | array of SaDocument | |
documents[].idrequired | string (uuid) | |
documents[].fileNamerequired | string | |
documents[].contentTyperequired | string | |
documents[].sizeBytesrequired | integer | |
documents[].statusrequired | string (SaDocumentStatus) | One of: |
documents[].rejectedReasonrequired | stringnullable | |
documents[].readingStatusrequired | string (SaDocumentReadingStatus) | One of: |
documents[].readingrequired | objectnullable | { documentType, taxYearShown, readings, warnings }. |
documents[].createdAtrequired | string (date-time) | |
planrequired | object (SaPlan) | Which pages and steps a return needs, from the answers so far. Nothing counts as a no until it’s answered. |
plan.questionnaireVersionrequired | string | |
plan.questionsrequired | array of SaQuestion | The questions that apply, given the answers. |
plan.questions[].idrequired | string | |
plan.questions[].textrequired | string | |
plan.questions[].help | string | |
plan.questions[].kindrequired | string (SaQuestionKind) | One of: |
plan.questions[].section | string | The SA100 section a yes opens. |
plan.questions[].outOfScope | object | { form, title }: a page Tolvi can’t prepare yet, if the answer is yes. |
plan.answersrequired | object | Answers so far. |
plan.unansweredrequired | array of string | |
plan.completerequired | boolean | |
plan.pagesNeededrequired | object | { sa102: 2, sa103s: 0, ... }. |
plan.outOfScoperequired | array of object | { form, title }: pages the answers call for that can’t be filed from Tolvi. |
plan.stepsrequired | array of SaPlanStep | |
plan.steps[].keyrequired | string | example "sa102.0" |
plan.steps[].titlerequired | string | |
plan.steps[].pagerequired | string | example "sa102" |
plan.steps[].instancerequired | integernullable | |
plan.steps[].boxesrequired | array of stringnullable | The boxes on this step. Null means every box on the page. |
plan.extraPagesrequired | array of object | { page, instance }: pages with figures the answers no longer call for. A person decides. |
plan.prepModerequired | string (SaPrepMode)nullable | How it’s being prepared, once someone has chosen. One of: |
plan.suggested | object | { questionId: { value, why } }: answers Tolvi can suggest from last year, the client’s record and what HMRC holds. None counts until a person accepts it. |
phaserequired | string (SaAiPhase) | What the next turn does: finds out what’s needed, fills the boxes, or acts on a request. One of: |
estimaterequired | object (SaAiEstimate)nullable | |
estimate.tokensrequired | integer | Tolvi AI tokens, about. |
estimate.affordablerequired | boolean | |
estimate.reasonrequired | stringnullable | |
replyrequired | object (SaAiMessage) | |
reply.idrequired | string (uuid) | |
reply.rolerequired | string (SaAiMessageRole) | One of: |
reply.textrequired | string | |
reply.outcomerequired | objectnullable | On an assistant’s turn: { applied, cleared, refused, answers, stillNeeded, tokens }. |
reply.createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Have AI Mode fill the boxes
POST/api/v1/self-assessment/returns/{id}/ai/complete
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
Preparers and above, on a draft, once the questions are answered. Spends the firm’s Tolvi AI tokens. It fills only what the evidence supports. A person then checks each figure.
Needs the Preparer role or above. Part of the self_assessment 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 (SaAiTurn).
One turn of AI Mode. Every figure was read from the evidence it cites by Tolvi, not the model.
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).
Confirm figures AI filled
POST/api/v1/self-assessment/returns/{id}/ai/confirm
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
Preparers and above, signed in. Records who checked each figure. Doesn’t change the figures or approve anything. Never available to connected assistants.
Needs the Preparer role or above. Part of the self_assessment 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 (ConfirmSaAiFiguresRequest).
| Field | Type | Description |
|---|---|---|
boxKeysrequired | array of string | Boxes you have checked, keyed sa102.0.EMP1. |
Responses
200 OK, application/json
Body: object (SaReturn).
A client’s SA100 for one tax year, with the calculation and what stands in the way of filing.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Add a document for AI Mode
POST/api/v1/self-assessment/returns/{id}/documents
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
A PDF or photo, such as a P60. Returns where to upload it. Nothing reads it until the malware scan is clean.
Needs the Preparer role or above. Part of the self_assessment 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 (CreateSaDocumentRequest).
| Field | Type | Description |
|---|---|---|
fileNamerequired | string | 1 to 200 characters; example "P60 2026.pdf" |
contentTyperequired | string | example "application/pdf" |
sizeBytesrequired | integer |
Responses
201 Created, application/json
Body: object (SaDocumentUpload).
| Field | Type | Description |
|---|---|---|
documentrequired | object (SaDocument) | |
document.idrequired | string (uuid) | |
document.fileNamerequired | string | |
document.contentTyperequired | string | |
document.sizeBytesrequired | integer | |
document.statusrequired | string (SaDocumentStatus) | One of: |
document.rejectedReasonrequired | stringnullable | |
document.readingStatusrequired | string (SaDocumentReadingStatus) | One of: |
document.readingrequired | objectnullable | { documentType, taxYearShown, readings, warnings }. |
document.createdAtrequired | string (date-time) | |
uploadrequired | object | { url, headers, expiresAt }: PUT the file here. |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Finish uploading a document
POST/api/v1/self-assessment/returns/{id}/documents/{documentId}/complete
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
Checks the stored file and starts the malware scan.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
documentIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (SaDocument).
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
fileNamerequired | string | |
contentTyperequired | string | |
sizeBytesrequired | integer | |
statusrequired | string (SaDocumentStatus) | One of: |
rejectedReasonrequired | stringnullable | |
readingStatusrequired | string (SaDocumentReadingStatus) | One of: |
readingrequired | objectnullable | { documentType, taxYearShown, readings, warnings }. |
createdAtrequired | string (date-time) |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Have AI Mode read a document
POST/api/v1/self-assessment/returns/{id}/documents/{documentId}/read
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
Spends the firm’s Tolvi AI tokens. Refused until the malware scan is clean.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
documentIdrequired | 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).
Get a link to a document
GET/api/v1/self-assessment/returns/{id}/documents/{documentId}/download
- Scopes
self_assessment:read
Refused until the malware scan is clean. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
documentIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object.
| Field | Type | Description |
|---|---|---|
urlrequired | string | |
expiresAtrequired | string |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Remove a document
DELETE/api/v1/self-assessment/returns/{id}/documents/{documentId}
- Scopes
self_assessment:write- Role
- Preparer or above
- Access
- A signed-in Tolvi session only, never an API token.
Deletes the file. Figures already taken from it stay on the return with the record of where they came from.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
idrequired | path | string (uuid) | |
documentIdrequired | 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).
List HMRC accounts
GET/api/v1/self-assessment/agent-accounts
- Scopes
self_assessment:read
Names and status only: a saved sign-in is never returned. Part of the self_assessment product: the firm must have it and you must have access to it.
Responses
200 OK, application/json
Body: object (SaAgentAccountList).
| Field | Type | Description |
|---|---|---|
itemsrequired | array of SaAgentAccount | |
items[].idrequired | string (uuid) | |
items[].namerequired | string | |
items[].credentialStatusrequired | string (SaCredentialStatus) | One of: |
items[].userIdHintrequired | stringnullable | The last characters of the user ID, to tell accounts apart. |
items[].lastUsedAtrequired | string (date-time)nullable | |
items[].connectionStatusrequired | string (SaConnectionStatus) | One of: |
items[].grantExpiresAtrequired | string (date-time)nullable | HMRC’s authority ends 18 months after it was given. |
items[].reconnectSoonrequired | boolean | |
hmrcAvailablerequired | boolean | Whether Tolvi can reach HMRC on this deployment. |
canStoreCredentialsrequired | boolean | Whether this deployment can store sign-ins (encryption is set up). |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Add an HMRC account
POST/api/v1/self-assessment/agent-accounts
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Firm admins, signed in. Name it so people can tell them apart, such as Leeds office. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object (CreateSaAgentAccountRequest).
| Field | Type | Description |
|---|---|---|
namerequired | string | 1 to 80 characters; example "Leeds office" |
Responses
201 Created, application/json
Body: object (SaAgentAccount).
A named HMRC agent account. Its sign-in and HMRC’s grant are never returned.
| Field | Type | Description |
|---|---|---|
idrequired | string (uuid) | |
namerequired | string | |
credentialStatusrequired | string (SaCredentialStatus) | One of: |
userIdHintrequired | stringnullable | The last characters of the user ID, to tell accounts apart. |
lastUsedAtrequired | string (date-time)nullable | |
connectionStatusrequired | string (SaConnectionStatus) | One of: |
grantExpiresAtrequired | string (date-time)nullable | HMRC’s authority ends 18 months after it was given. |
reconnectSoonrequired | boolean |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Rename an HMRC account
PATCH/api/v1/self-assessment/agent-accounts/{id}
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Firm admins, signed in. Part of the self_assessment 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 (CreateSaAgentAccountRequest).
| Field | Type | Description |
|---|---|---|
namerequired | string | 1 to 80 characters; example "Leeds office" |
Responses
200 OK, application/json
Body: object (SaAgentAccount).
A named HMRC agent account. Its sign-in and HMRC’s grant are never returned.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Remove an HMRC account
DELETE/api/v1/self-assessment/agent-accounts/{id}
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Firm admins, signed in. Its sign-in and HMRC’s grant are deleted at once. Part of the self_assessment 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).
Save the HMRC sign-in
PUT/api/v1/self-assessment/agent-accounts/{id}/credentials
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Firm admins, signed in. Encrypted, used only when someone allowed to file files a return, and never shown again. Part of the self_assessment 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 (SaveSaCredentialsRequest).
Stored encrypted, used only when someone allowed to file files a return, and never returned by any route.
| Field | Type | Description |
|---|---|---|
userIdrequired | string | The HMRC online services user ID. |
passwordrequired | string (password) |
Responses
200 OK, application/json
Body: object (SaAgentAccount).
A named HMRC agent account. Its sign-in and HMRC’s grant are never returned.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Delete the saved sign-in
DELETE/api/v1/self-assessment/agent-accounts/{id}/credentials
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Firm admins, signed in. Part of the self_assessment 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 (SaAgentAccount).
A named HMRC agent account. Its sign-in and HMRC’s grant are never returned.
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).
Finish connecting to HMRC
POST/api/v1/self-assessment/agent-accounts/callback
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Posted by the page HMRC sends people back to, as the person who started. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object (SaHmrcCallbackRequest).
| Field | Type | Description |
|---|---|---|
coderequired | string | |
staterequired | string |
Responses
200 OK, application/json
Body: object (SaAgentAccount).
A named HMRC agent account. Its sign-in and HMRC’s grant are never returned.
The fields are as shown above.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Disconnect from HMRC
DELETE/api/v1/self-assessment/agent-accounts/{id}/connection
- Scopes
settings:admin- Access
- A signed-in Tolvi session only, never an API token.
Firm admins, signed in. Part of the self_assessment 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 (SaAgentAccount).
A named HMRC agent account. Its sign-in and HMRC’s grant are never returned.
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).
Work out an informal estate computation
POST/api/v1/self-assessment/informal-estate
- Scopes
self_assessment:write- Role
- Preparer or above
The year-by-year breakdown HMRC asks for by letter, and HMRC’s three tests for whether the informal route fits. Gains and Capital Gains Tax are as entered. Keeps nothing. Body: deceasedName, dateOfDeath, administrationEnded, estateValuePence, years[].
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object.
Responses
200 OK, application/json
Body: object.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Download an informal estate computation
POST/api/v1/self-assessment/informal-estate/pdf
- Scopes
self_assessment:write- Role
- Preparer or above
As a PDF, for a person to check and send with their letter. Same body.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object.
Responses
200 OK
A PDF.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Work out a trust accounts pack
POST/api/v1/self-assessment/trust-accounts
- Scopes
self_assessment:write- Role
- Preparer or above
Capital and income apart, a distribution statement and whether the assets agree. No statutory format was found for a non-charitable trust: this is a working layout. Keeps nothing.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object.
Responses
200 OK, application/json
Body: object.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Download a trust accounts pack
POST/api/v1/self-assessment/trust-accounts/pdf
- Scopes
self_assessment:write- Role
- Preparer or above
As a PDF. Same body.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object.
Responses
200 OK
A PDF.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Work out an R40 schedule
POST/api/v1/self-assessment/r40
- Scopes
self_assessment:write- Role
- Preparer or above
The figures for a repayment claim, and whether the R40 can be used. HMRC publishes no schema for it that could be found, so it can’t be sent from Tolvi and the repayment isn’t worked out. Keeps nothing.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object.
Responses
200 OK, application/json
Body: object.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
Download an R40 schedule
POST/api/v1/self-assessment/r40/pdf
- Scopes
self_assessment:write- Role
- Preparer or above
A schedule to key from or post with evidence. It isn’t HMRC’s form. Same body.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Request body
Required. application/json: object.
Responses
200 OK
A PDF.
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 429 Too many requests, as problem details (application/problem+json).
A trust’s registration and what’s due
GET/api/v1/self-assessment/trust-registrations/{clientId}
- Scopes
self_assessment:read- Role
- Preparer or above
What the practice has recorded. HMRC’s Trust Registration Service has no API that could be found, so this doesn’t come from HMRC.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Responses
200 OK, application/json
Body: object (TrustRegistration).
| Field | Type | Description |
|---|---|---|
clientIdrequired | string (uuid) | |
referencerequired | stringnullable | The UTR or Unique Reference Number HMRC gave. |
registeredOnrequired | string (date)nullable | example "2026-03-31" |
taxablerequired | boolean | |
liableTaxYearEndsrequired | array of number | |
declaredTaxYearEndsrequired | array of number | |
changeAwareOnrequired | string (date)nullable | example "2026-03-31" |
duerequired | array of TrustRegistrationDue | |
due[].kindrequired | string | |
due[].duerequired | string (date) | example "2026-03-31" |
due[].labelrequired | string | |
due[].taxYearEnd | integer | |
remindersOnrequired | boolean |
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).
Record a trust’s registration
PUT/api/v1/self-assessment/trust-registrations/{clientId}
- Scopes
self_assessment:write- Role
- Preparer or above
The reference, whether it’s taxable, years of liability and what’s been confirmed. Reminders follow when they’re on.
Needs the Preparer role or above. Part of the self_assessment product: the firm must have it and you must have access to it.
Parameters
| Name | In | Type | Description |
|---|---|---|---|
clientIdrequired | path | string (uuid) |
Request body
Required. application/json: object.
Responses
Errors: 400 Bad request, 401 Unauthorised, 403 Forbidden, 404 Not found, 429 Too many requests, as problem details (application/problem+json).