hmrc-exchange-rate — HM Revenue & Customs exchange rates for Node.js
Official HM Revenue & Customs (United Kingdom) exchange rates in Node.js and TypeScript with the hmrc-exchange-rate npm package: latest published table, any historical date, daily series. Zero dependencies, types included.
rate_date — what tax filings, customs valuations, audits and compliant invoicing
require. For the live interbank midpoint use the mid-market API or
@allratestoday/sdk;
the two can differ by several percent.
Installation
npm install hmrc-exchange-rate
# or
yarn add hmrc-exchange-rate
pnpm add hmrc-exchange-rate
The same code is also published under the org scope as
@allratestoday/hmrc-exchange-rate — identical versions, pick
whichever naming fits your dependency policy. Zero runtime dependencies; ESM and CommonJS
builds; TypeScript definitions included.
Quick start
You need a free API key from allratestoday.com/register — no credit card, and the latest HM Revenue & Customs table is on every plan.
import { getRate } from 'hmrc-exchange-rate';
const pair = await getRate('GBP', 'USD', { apiKey: 'art_live_...' });
console.log(pair.rate, pair.rate_date);
// the official HM Revenue & Customs rate, on the tax authority's own publication date API reference
Four functions, all returning promises. Every function takes an options object with your
apiKey; the package throws before making a request if it is missing.
getRate(source, target, options)
Free plan and up. One pair from the latest published table. Pairs HM Revenue & Customs does not print directly are resolved from its own table and flagged (see published vs derived).
const pair = await getRate('GBP', 'USD', { apiKey: 'art_live_...' });
// →
{
bank: 'hmrc',
name: 'HM Revenue & Customs',
rate_date: '2026-08-21', // HM Revenue & Customs's own publication date
source: 'GBP',
target: 'USD',
rate: 0.854774,
rate_type: 'reference',
derived: false,
method: 'published', // 'published' | 'inverse' | 'cross'
disclaimer: '…'
} getLatestRates(options)
Free plan and up. The complete table for the latest publication date — one call, every currency HM Revenue & Customs prints.
import { getLatestRates } from 'hmrc-exchange-rate';
const table = await getLatestRates({ apiKey: 'art_live_...' });
console.log(table.rate_date, table.rates.length);
// →
{
bank: 'hmrc',
name: 'HM Revenue & Customs',
rate_date: '2026-08-21',
rates: [
{ base: 'GBP', quote: 'USD', type: 'reference', value: 1.1699 },
// … the rest of the published table
],
disclaimer: '…'
} getRatesForDate(date, options)
Paid plans. The official table for any past date. Weekends and holidays return the most
recent published table, flagged via published_on_requested_date — exactly the
in-force rate a filing or invoice needs. Pass source/target in the
options to narrow to one pair.
import { getRatesForDate } from 'hmrc-exchange-rate';
const day = await getRatesForDate('2026-06-30', { apiKey: 'art_live_...' });
const one = await getRatesForDate('2026-06-30', { apiKey: 'art_live_...', source: 'GBP', target: 'USD' });
// →
{
bank: 'hmrc',
requested_date: '2026-06-30',
rate_date: '2026-06-30', // the date actually published
published_on_requested_date: true, // false when a weekend/holiday fell back
rates: [ /* the full table for that date */ ],
disclaimer: '…'
} getHistory(query, options)
Paid plans. One resolved rate per publication date across a range — for charts, revaluation
runs or audit workpapers. Pass { symbol: 'GBP' } instead of
source/target to get the raw published rows for one currency.
import { getHistory } from 'hmrc-exchange-rate';
const series = await getHistory(
{ source: 'GBP', target: 'USD', from: '2026-01-01', to: '2026-08-21' },
{ apiKey: 'art_live_...' }
);
// →
{
bank: 'hmrc',
source: 'GBP',
target: 'USD',
from: '2026-01-01',
to: '2026-08-21',
count: 152,
rates: [
{ date: '2026-08-21', rate: 0.854774, rate_type: 'reference', derived: false, method: 'published' },
// … one entry per publication date
],
disclaimer: '…'
} Published vs derived rates
If HM Revenue & Customs does not print a pair directly, the API resolves it from the tax authority's own table and says so — official and computed values are never mixed:
method | derived | Meaning |
|---|---|---|
published | false | HM Revenue & Customs printed this pair directly |
inverse | true | Computed as 1 ÷ the published opposite direction |
cross | true | Computed via GBP from two published rates |
Error handling
Errors are thrown as Error with status (HTTP code) and body (the API's JSON error) attached:
try {
const pair = await getRate('GBP', 'XXX', { apiKey: 'art_live_...' });
} catch (err) {
console.log(err.message); // human-readable reason
console.log(err.status); // e.g. 404
} | Status | Meaning |
|---|---|
| — | Missing apiKey (thrown before any request) |
400 | Malformed date or parameters |
401 | Invalid API key |
403 | Endpoint needs a paid plan (historical dates & series) |
404 | Pair or date range not covered by HM Revenue & Customs |
429 | Quota exceeded |
TypeScript and CommonJS
Full definitions ship with the package — no @types install:
import type { LatestRates, PairRate, DatedRates, RateEntry, HistoryQuery, RequestOptions } from 'hmrc-exchange-rate'; CommonJS works too:
const { getRate } = require('hmrc-exchange-rate');
getRate('GBP', 'USD', { apiKey: 'art_live_...' }).then((pair) => console.log(pair.rate)); Quota tips
- HM Revenue & Customs publishes every business day — cache the table locally and a small monthly quota goes a long way.
- Every request counts toward your AllRatesToday quota, shared across all endpoints on your key.
- Prefer
getLatestRates(one call, whole table) over manygetRatecalls when you need several pairs.
Under the hood
The package is a thin, dependency-free wrapper over the REST endpoints documented on the HM Revenue & Customs rates page:
GET /api/v1/central-bank/hmrc/latest?source=GBP&target=USD
GET /api/v1/central-bank/hmrc/latest
GET /api/v1/central-bank/hmrc/2026-06-30
GET /api/v1/central-bank/hmrc/history?source=GBP&target=USD&from=2026-01-01&to=2026-08-21 Same data is available as CSV/XLSX downloads on the no-code download page, and to AI agents via the MCP server.
FAQ
Is hmrc-exchange-rate free to use?
Yes. The package is MIT-licensed and the latest published HM Revenue & Customs table is available on the free AllRatesToday plan. Historical dates and daily series need a paid plan.
Are these the same numbers HM Revenue & Customs publishes?
Yes. Every value is the tax authority's own published figure, carrying its own rate_date. Pairs the tax authority does not print directly are resolved from its table and flagged derived: true.
Does hmrc-exchange-rate work in the browser or on edge runtimes?
It runs anywhere a global fetch exists — Node 18+, Bun, Deno, Cloudflare Workers and similar. Keep your API key server-side; do not ship it in browser bundles.
Get your free API key
Latest HM Revenue & Customs rates on every plan. Historical dates and series from €4.99/month.
Create a free account See pricing