Skip to main content

~151 routesAuthenticatedTenant-scopedPermission-checkedAudit-logged

Read one response and you will know.

Every high-risk answer returns the same standardised contract. It is unusually long for an API response, and every field in it is there because leaving it out would let a client present something as exact when it is not.

The answer contract

This is a real response for the documented golden UK computation — the same £11,432 every other surface on this site shows. Two fields decide what your interface is allowed to do with it: coverage_status, which says whether the figure may be presented as exact, and verification_status, which is the field to branch on.

POST /api/v1/tax-assistant/answer — 200
JSON
{
  "answer_type": "calculation",
  "jurisdictions": [
    "GB"
  ],
  "tax_years": [
    "2024/25"
  ],
  "tax_types": [
    "individual_income"
  ],
  "coverage_status": "beta",
  "law_as_of": "2024-04-06",
  "source_last_checked": "2024-11-03",
  "corpus_release_id": "uk-2024-11-03.a41f9c",
  "facts_used": [
    {
      "key": "employment_income",
      "value": "60000.00",
      "currency": "GBP"
    },
    {
      "key": "sub_region",
      "value": "rest_of_uk"
    },
    {
      "key": "filing_status",
      "value": "individual"
    }
  ],
  "missing_facts": [],
  "calculations": [
    {
      "calculator": "uk_income_tax",
      "calculator_version": "2024.3.1",
      "parameter_dataset": "UK/2024-25",
      "taxable_income": "47430.00",
      "total_tax": "11432.00",
      "effective_rate": "0.1905",
      "marginal_rate": "0.40",
      "bands": [
        {
          "label": "Personal allowance",
          "amount": "12570.00",
          "rate": "0.00",
          "tax": "0.00"
        },
        {
          "label": "Basic rate",
          "amount": "37700.00",
          "rate": "0.20",
          "tax": "7540.00"
        },
        {
          "label": "Higher rate",
          "amount": "9730.00",
          "rate": "0.40",
          "tax": "3892.00"
        }
      ]
    }
  ],
  "claims": [
    {
      "id": "c1",
      "type": "figure",
      "text": "Income tax due is £11,432.00.",
      "support": "calculator",
      "calculation_ref": "uk_income_tax",
      "verified": true
    },
    {
      "id": "c2",
      "type": "rate",
      "text": "The basic rate is 20% on taxable income up to £37,700.",
      "support": "citation",
      "citation_ref": "s1",
      "verified": true
    }
  ],
  "citations": [
    {
      "id": "s1",
      "authority": "UK Parliament",
      "authority_rank": "statute",
      "title": "Income Tax Act 2007",
      "locator": "s.10",
      "effective_from": "2007-04-06",
      "stale": false
    },
    {
      "id": "s2",
      "authority": "HMRC",
      "authority_rank": "guidance",
      "title": "Income Tax rates and Personal Allowances",
      "locator": "2024 to 2025",
      "effective_from": "2024-04-06",
      "stale": false
    }
  ],
  "assumptions": [
    "Rest-of-UK rates. Scotland has different income tax bands.",
    "No other income, reliefs or allowances beyond the personal allowance."
  ],
  "risks": [
    "A Scottish taxpayer would produce a different figure from the same income."
  ],
  "confidence": 0.97,
  "verification_status": "verified",
  "human_review_required": false,
  "request_classification": "high_risk",
  "answer_mode": "grounded",
  "conflicts": [],
  "next_actions": [
    "Review before filing."
  ]
}

Note what is not optional. missing_facts, conflicts and assumptions are present on every high-risk answer, empty on a clean one. A client that treats them as sometimes-absent will break on the interesting case rather than on a release.

A real request

The same call in three forms. Whichever you pick, the branch is on verification_status — not on whether a number came back, because an abstention is a successful response with no number in it.

request.sh
Shell
curl -X POST https://api.taxorch.com/api/v1/tax-assistant/answer \
  -H "Authorization: Bearer $TAXORCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "What is the income tax on £60,000 in the UK for 2024/25?",
    "jurisdiction": "GB",
    "tax_year": "2024/25",
    "site": 1
  }'

Response conventions

These are worth reading before you write a client. Two of them are unusual, and both exist so that a failure tells you what to do rather than only that something went wrong.

The answer contract
Every high-risk answer returns the same standardised object, whatever the endpoint. You parse one shape rather than one per surface.
422 with a blocker list
An operation is blocked by an unmet precondition, and the response says exactly which. Not a generic validation failure — a list of what to fix.
409 Conflict
The target record is immutable. A finalised case is the common one: reopening it is a deliberate, audited action rather than a permitted write.
verification_status
Eight values, covering the outcomes nobody wants as well as the good one. This is the field to branch on.
X-Content-SHA256
Returned on audit-proof downloads, so a client can verify integrity itself rather than trusting the transfer.
Contract headers
Each surface pins its API contract version, so a client can detect a breaking change rather than discovering one.

The shape of the API

Approximately 151 routes, counted from the URL configuration rather than estimated. Every endpoint is authenticated, tenant-scoped, permission-checked and audit-logged — those are not four features, they are four things you cannot turn off.

  • Authenticated
  • Tenant-scoped
  • Permission-checked
  • Audit-logged

The base prefix is /api/. Versioned actions are mirrored under /api/v1/, and each surface pins its own contract version in a response header — so a breaking change is something a client can detect rather than something it discovers. Most endpoints accept ?site=<id> and enforce per-site permission on top of the tenant scope.

Where to go next

  • Quickstart

    A grounded answer from a cold start, in one request.

    Read
  • The answer contract

    Every field annotated, with all four outcomes side by side.

    Read
  • API reference

    Every endpoint, grouped by the surface it belongs to.

    Read
  • Self-hosting

    Profiles, configuration and the readiness gates.

    Read
  • SDKs

    Client libraries, and what they do and do not wrap.

    Read
Start reading

The quickest way to judge this is the API.

The answer contract states what every response carries, including the shape of a refusal. Nothing about it is hidden behind a sales conversation.