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.

HM Revenue & Customs · United Kingdom · home currency GBP · published every business day
Official rate, not mid-market. Every value this package returns is a number HM Revenue & Customs itself published, fixed once printed and carrying the tax authority's own 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:

methodderivedMeaning
publishedfalseHM Revenue & Customs printed this pair directly
inversetrueComputed as 1 ÷ the published opposite direction
crosstrueComputed 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
}
StatusMeaning
Missing apiKey (thrown before any request)
400Malformed date or parameters
401Invalid API key
403Endpoint needs a paid plan (historical dates & series)
404Pair or date range not covered by HM Revenue & Customs
429Quota 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

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