vatverify home
All guides

HMRC VAT check API: UK VAT validation explained

How HMRC's VAT check API works. OAuth 2.0 client credentials, sandbox vs production, rate limits, and why vatverify handles all of it for you.

TL;DR

  • HMRC is the UK's VAT registry, completely separate from VIES since Brexit.
  • It is a proper REST API (JSON in, JSON out), which is the good news.
  • The bad news: it requires OAuth 2.0 client credentials, token refresh every hour, and a ~10-day production application process.
  • vatverify handles the OAuth dance, token caching, and retries so you never touch any of it.

Why UK VAT is different from EU

Before Brexit, UK VAT numbers (GB prefix) were accessible through VIES just like any other EU member state. After 1 January 2021, Great Britain left the EU VAT area and HMRC became the sole authoritative registry for GB-prefixed numbers. Northern Ireland is a special case: XI-prefixed numbers remain in scope of EU VAT rules under the Windsor Framework and are still validated through VIES. So in practice: if the prefix is GB, query HMRC; if the prefix is XI, query VIES.

HMRC REST vs VIES SOAP

The HMRC API is genuinely pleasant to work with at the protocol level: REST, JSON, predictable status codes. The friction is entirely in the auth layer: you need OAuth 2.0 client credentials (not just an API key) and you need to renew the access token every 60 minutes. Compare that to VIES, which has no auth at all but forces you through SOAP/XML. Both registries have real operational complexity; they just put it in different places.

UK VAT number format

UK VAT numbers follow one of two patterns:

  • Standard: GB + 9 digits, e.g., GB123456789
  • Branch code: GB + 9 digits + 3-digit branch suffix, e.g., GB123456789012

Some older references also show a 4-digit government department prefix (GBGD or GBHA) but these are rare and handled automatically by vatverify.

The 9 core digits use the HMRC 97-55 checksum algorithm to detect transposition errors.

HMRC 97-55 checksum

The algorithm is named after the two valid modular remainders (42 and 55 are also valid, but 97 is the modulus, hence "97-55"). To verify a 9-digit VAT number:

hmrc-checksum.ts
function hmrc9755Checksum(digits: string): boolean {
  const nums = digits.split('').map(Number);
  const sum = nums.slice(0, 7).reduce((a, d, i) => a + d * (8 - i), 0);
  const expected = (sum + Number(digits.slice(7, 9))) % 97;
  return expected === 0 || expected === 42 || expected === 55; // ← the 97-55 name
}

The weights for positions 1–7 are 8, 7, 6, 5, 4, 3, 2. You multiply each digit by its weight, sum the results, add the two-digit check suffix (digits 8–9), and check that the total is divisible by 97 with a remainder of 0, 42, or 55. The 42 and 55 variants were introduced to accommodate a specific range of registration numbers issued in a particular period. Any offline validation library worth using (including @vatverify/vat-rates) implements all three variants.

OAuth 2.0 client credentials flow

The flow in plain prose:

  1. POST to https://api.service.hmrc.gov.uk/oauth/token with grant_type=client_credentials, your client_id, and client_secret.
  2. HMRC returns a JSON body with access_token, token_type: "bearer", and expires_in: 14400 (4 hours for production, shorter in sandbox).
  3. Include Authorization: Bearer <access_token> on every subsequent request.
  4. Re-request a token before it expires. Best practice is to re-request at ~55 minutes (5-minute safety buffer) regardless of the expires_in value.

The validation endpoint itself is straightforward once you have a token:

GET https://api.service.hmrc.gov.uk/organisations/vat/check-vat-number/lookup/{targetVatNumber}

Sandbox vs production

SandboxProduction
Base URLhttps://test-api.service.hmrc.gov.ukhttps://api.service.hmrc.gov.uk
CredentialsAny test credentialsApproved application required
Response dataCanned fixture data onlyLive HMRC registry
Token TTLShorter (varies)4 hours
AvailabilityAlways openRequires production approval

The sandbox is free and open. It returns a fixed set of test VAT numbers with predictable responses, useful for integration testing, but it will never return a "real" company name because no live data is exposed.

Production access application

To get production credentials, you register an application at developer.service.hmrc.gov.uk, select the VAT (MTD) API, and request the read:vat scope (the scope for check-vat-number lookups). HMRC reviews applications manually; expect approximately 10 working days. During review they check your stated use case, your privacy policy, and that your callback URLs are reachable. Once approved, you receive production client_id and client_secret through the developer portal. Store them in environment variables, never in source code.

Token caching

Re-requesting a token on every API call is wasteful and slows your response times. Cache the token for 55 minutes (using a 5-minute safety buffer against the 60-minute TTL). Using a key-value store:

SET hmrc:token <access_token> EX 3300

3300 seconds = 55 minutes. Before each HMRC request, check whether hmrc:token exists. If it does, use it. If it doesn't, run the OAuth token exchange, store the result, then proceed.

vatverify handles all of this internally. The token lifecycle is invisible to you.

MTD (Making Tax Digital) context

HMRC is migrating all tax operations to API-first under the Making Tax Digital programme. VAT validation is the simplest endpoint in the MTD ecosystem, but understanding it gives you a foundation for MTD filing integrations. The check-vat-number scope is a read-only permission. It does not give you access to return submission or payment data. That is intentional: validation is separate from filing.

Direct HMRC vs vatverify

FeatureDirect HMRCvatverify
ProtocolREST/JSONREST/JSON
AuthOAuth 2.0 (manual)Handled internally
Token lifecycleYou manage rotationAutomatic
CachingNone (you build it)30-day automatic
RetriesNone (you build it)Automatic with backoff
Production approval~10-day process on your accountvatverify's approved credentials
Rate limit~100 req/secUnbounded (cached)
Northern Ireland (XI)Separate VIES callAutomatic routing

FAQ

How do I get production credentials?

Apply at developer.service.hmrc.gov.uk. Select the VAT (MTD) API, request the read:vat scope, and submit your application. HMRC reviews manually. Budget approximately 10 working days. If you use vatverify, you skip this step entirely because the API calls go through vatverify's pre-approved credentials.

Can I use the free sandbox forever?

Yes. The HMRC sandbox has no expiry and no cost. The limitation is that it only returns canned fixture data: a fixed list of test VAT numbers with predetermined responses. It is not useful for validating real numbers or for any production scenario.

Does HMRC return company names?

Yes. The response includes a target object with a name field (the registered business name) and an address object with structured fields (line1, line2, line3, line4, postcode, countryCode). This is more structured than VIES, which returns a free-text address string for most countries.

What's the rate limit?

HMRC's published guidance suggests approximately 100 requests per second sustained from a single OAuth application. In practice the ceiling is higher, but 100 req/sec is a safe target if you are hitting HMRC directly. With vatverify, cached results do not count against any rate limit. Only cache misses result in upstream calls.

What about Northern Ireland VAT?

Northern Ireland VAT numbers use the XI prefix, not GB. These are validated through VIES, not HMRC, because Northern Ireland remains within the EU VAT area for goods under the Windsor Framework. vatverify routes automatically based on prefix: GB → HMRC, XI → VIES. You pass the number and let the API handle it.

Validate VAT in three lines.

Free up to 500 requests per month. No credit card.

Start free