Skip to content
lexratesAccount

API · 10 endpoints · verified 2026-09-23

Read-only, and it answers without a key.

Everything the corpus knew twelve months ago is open: no account, no key, no rate agreement. A key adds the current year, the future and the alert. Every response is JSON; every refusal is an RFC 9457 problem document with a URL you can follow.

base https://api.lexrates.com

Start hereno key required

One call, and the answer carries its own sources.

a figure, on a date the open tier covers
curl "https://api.lexrates.com/v1/compute?regime=gb-amap&vehicleClass=car-van&units=1000&on=2024-06-01"
what comes back · 200
{
  "regime": "gb-amap",
  "country": "GB",
  "on": "2024-06-01",
  "amount": 450,
  "currency": "GBP",
  "unit": "mi",
  "billableUnits": 1000,
  "steps": [
    "1000 × 0.45 = 450"
  ],
  "sources": [
    {
      "publisher": "gov.uk",
      "url": "https://www.gov.uk/government/publications/rates-and-allowances-travel-mileage-and-fuel-allowances/travel-mileage-and-fuel-rates-and-allowances",
      "verifiedOn": "2026-09-05"
    },
    {
      "publisher": "gov.uk — Claim tax relief for your job expenses: vehicles you use for work",
      "url": "https://www.gov.uk/tax-relief-for-employees/vehicles-you-use-for-work",
      "verifiedOn": "2026-09-02"
    }
  ],
  "nextReviewDue": "2027-04-05"
}
the same call inside the last twelve months
curl "https://api.lexrates.com/v1/compute?regime=gb-amap&vehicleClass=car-van&units=1000&on=2026-06-01"
# → 402, naming the most recent open period

curl -H "Authorization: Bearer YOUR_KEY" \
  "https://api.lexrates.com/v1/compute?regime=gb-amap&vehicleClass=car-van&units=1000&on=2026-06-01"
# → 200

A key in the query string works too and is the weaker form: ?key= travels into CDN logs, browser history and cache keys, where a header does not. Prefer the header.

YOUR_KEY comes from your account: create one, subscribe, and the key is on that page from then on — it is attached to the account rather than handed over once, so losing it is not an incident. What the subscription costs, and what the open tier gives you without one, is on the pricing page.

The two time axeson · knownOn

Ask what applied, or ask what you could have known.

on
The date the journey happened, or the day being paid. Absent, today. This is the axis everybody expects.
knownOn
The date you are pretending to stand on. Absent, everything known is used. Set it to reproduce a run you made in the past: a text published in March and retroactive to January did not exist in February, and a reconciliation that ignores that reads as a defect in your product rather than in the gazette.
reproduce a February run, before a retroactive text existed
curl "https://api.lexrates.com/v1/compute?regime=nz-ird-kilometre-rates&vehicleClass=petrol\
&units=500&on=2025-09-01&knownOn=2026-01-01"
# → 404 no-figure-in-force: that instrument was made in June 2026.

Asking knownOn explicitly is a paid question, whatever the answer would have been: asking what was published after the open-tier line is a question about today.

Endpoints10 documented
Every endpoint the API serves, generated from its OpenAPI document
PathWhat it answersQuery
/v1Service index
/v1/catalogue· csvEvery regime of every domain, with days remaining before its figures expire
  • domain
  • format
/v1/regimes/{id}One regime and its periods
  • id*
/v1/countries/{code}Every regime published in one country
  • code*
/v1/computeApply a regime to a distance on a date
  • regime*
  • vehicleClass*
  • units*
  • on
  • knownOn
  • modifiers
  • passengers
  • alreadyClaimed
  • paidPerUnit
  • use
/v1/per-diem/computeA day of per-diem meal allowance
  • regime*
  • paidPerDay
  • kind*
  • on
  • knownOn
  • hours
  • meals
  • use
  • destination
/v1/changes· csvEvery date a figure moved
  • since
  • format
/v1/alertsWhat is about to expire
  • within
/v1/openapi.jsonThis document
/healthLiveness

* required · csv also answers ?format=csv

Only two paths serve CSV, and that is a decision rather than an omission: a statutory figure can be a flat rate, marginal bands, a bracket formula with a fixed part, or a pair of day rates across hundreds of destinations. A CSV of the figures would be one number per row, which is the shape this product exists to say is wrong. The catalogue and the change log are genuinely tabular, so they serve it.

https://api.lexrates.com/v1/openapi.json — generate a client from it.

When it refuses10 named failures
Every refusal the API can return
StatusTypeWhen
404not-foundThe id or country code in the path is not one this corpus publishes.
400bad-requestA parameter is missing, blank, out of range, or not a value this endpoint accepts. A blank parameter is malformed rather than zero: ?units= means a field somebody meant to fill.
402outside-the-open-windowThe date asked about falls inside the last twelve months, or knownOn asks what was known after the cut — which is a question about today.
404no-figure-in-forceThe regime exists and holds no period covering that date.
404no-national-figureThe country publishes no single rate — Italy sets it per vehicle model in the ACI tables.
400wrong-domainA per-diem regime was sent to /v1/compute, or a mileage regime to /v1/per-diem/compute.
401key-requiredAn account path was called with no credential. Unlike /v1, these have no open tier: they answer about one subscription and cannot do that without knowing which.
401invalid-keyA credential was presented and cannot be read, or is not a key this service knows. Sending an unreadable Authorization header counts: it is never treated as an anonymous request.
405method-not-allowedThe path is right and the method is not. This API is read-only.
503budget-exceededA per-caller or service-wide ceiling was reached. The ceilings exist because a public endpoint spends unattended; they are stated on the pricing page.

Each type is a URL that resolves to a page explaining the failure and what to do about it. That is what RFC 9457 asks the field to be, and it is checked in both directions: no refusal can name a page that does not exist, and no page can document a refusal the API never returns.

What it costs to callenforced, not printed

The ceiling is in the code, and these are the numbers it enforces.

Anonymous
1,000
requests a day, per caller. The open tier is meant to be sampled, not mirrored.
With a key
100,000
requests a day.
Whole service
2,000,000
requests a month — a stop against a runaway client, not a billing meter.

Every answer carries x-ratelimit-limit and x-ratelimit-remaining. A closed period is settled arithmetic over settled figures, so it is cacheable for an hour and carries an ETag; an authenticated answer is never cached by anything.

Get a key