HMRC VAT Check API: A Developer's Guide to UK VAT Validation
Since Brexit, UK VAT numbers (GB prefix) are no longer in the EU's VIES system. To validate UK VAT numbers, you need to integrate with HMRC's "Check a UK VAT Number" API. This guide covers how the HMRC API works, its authentication requirements, common pain points, and how to avoid building the integration from scratch.
What is the HMRC VAT Check API?
HMRC (Her Majesty's Revenue and Customs) provides the "Check a UK VAT Number" API, also called the VAT Registered Companies API. It's a REST API (not SOAP like VIES), but it comes with its own complexity: OAuth 2.0 authentication, a sandbox/production split, and an application approval process.
The API validates whether a GB-prefixed VAT number is registered and active, and returns the company name, address, and effective dates.
Authentication: the OAuth 2.0 flow
This is the main pain point. HMRC uses OAuth 2.0 with the client credentials grant for server-to-server access. The flow:
- Register an application on the HMRC Developer Hub
- Receive a Client ID and Client Secret
- Request an access token from
https://api.service.hmrc.gov.uk/oauth/token - Include the token as a Bearer header on API requests
- Tokens expire (typically 4 hours), so you need to handle token refresh
The token request:
curl -X POST https://api.service.hmrc.gov.uk/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"The response:
{
"access_token": "HMRC_ACCESS_TOKEN",
"token_type": "bearer",
"expires_in": 14400
}Making a validation request
Once you have an access token, you can validate a VAT number. Note that HMRC strips the "GB" prefix, so you pass just the 9 digits:
curl https://api.service.hmrc.gov.uk/organisations/vat/check-vat-number/lookup/123456789 \
-H "Authorization: Bearer HMRC_ACCESS_TOKEN" \
-H "Accept: application/vnd.hmrc.2.0+json"A successful response:
{
"target": {
"name": "ACME LTD",
"vatNumber": "123456789",
"address": {
"line1": "123 HIGH STREET",
"postcode": "SW1A 1AA",
"countryCode": "GB"
}
},
"processingDate": "2026-03-24T10:30:00Z"
}Invalid numbers return a 404 (not a structured "valid: false" response). Your code needs to treat 404 as "not registered" rather than an error.
Pain points of using HMRC directly
- OAuth 2.0 complexity: You need to manage the full token lifecycle (request, cache, refresh on expiry). For a simple validation check, this is a lot of overhead.
- Application approval: Getting production access requires submitting your application for review on the HMRC Developer Hub. The sandbox works immediately, but production approval can take days. During this time you cannot validate real VAT numbers.
- Sandbox vs production: HMRC has separate URLs for sandbox (
test-api.service.hmrc.gov.uk) and production (api.service.hmrc.gov.uk), with separate credentials. You need to manage both environments. - No batch endpoint: Like VIES, HMRC only validates one number per request. Bulk validation requires sequential requests with your own rate limit handling.
- Error responses: Invalid numbers return 404, not a structured validation result. Rate limits return 429. Server errors return 500 with inconsistent error objects.
- Accept header versioning: You must include the correct
Acceptheader with the API version (e.g.,application/vnd.hmrc.2.0+json). Getting this wrong results in cryptic 406 responses.
How Vatly simplifies UK VAT validation
Vatly wraps HMRC (alongside VIES for EU, and national tax authorities for CH, LI, NO, and AU) so you never deal with OAuth, token management, or environment-specific URLs. The same endpoint works for EU, UK, Swiss, Liechtenstein, Norwegian, and Australian numbers:
# EU number (routes to VIES)
curl https://api.vatly.dev/v1/validate?vat_number=DE123456789 \
-H "Authorization: Bearer vtly_live_your_api_key"
# UK number (routes to HMRC)
curl https://api.vatly.dev/v1/validate?vat_number=GB123456789 \
-H "Authorization: Bearer vtly_live_your_api_key"Same response format, same error codes, same caching behavior. No OAuth dance, no environment switching, no application approval.
- Bearer token auth: Your Vatly API key is all you need. No OAuth flow, no token refresh.
- Same response envelope for all countries: One consistent format regardless of whether the number routes to VIES, HMRC, or another national tax authority.
- 25-day caching with stale fallback: When HMRC is unavailable, cached results are returned with
meta.cached: true. - Test mode with magic numbers:
GB111111111always returns valid. No sandbox credentials, no approval process. - Structured error responses: Machine-readable error codes instead of HTTP status guessing. Every error includes a code, message, and HTTP status.
For the EU equivalent, see the VIES API guide.
Get started
Vatly's free tier includes 500 validations per month, covering EU, UK, Swiss, Liechtenstein, Norwegian, and Australian numbers. No credit card required.
Frequently asked questions
Do I need OAuth to validate UK VAT numbers?
If you use the HMRC API directly, yes. HMRC requires OAuth 2.0 client credentials authentication with token management and refresh. Vatly abstracts this entirely, so you use a simple Bearer token (your API key) for all validations regardless of country.
How long does HMRC application approval take?
HMRC sandbox access is immediate, but production approval typically takes several business days. During this time, you cannot validate real UK VAT numbers through the HMRC API directly. Vatly provides immediate access to UK validation with no approval process.
Why does HMRC return 404 for invalid VAT numbers?
HMRC treats unregistered VAT numbers as 'not found' resources rather than returning a structured validation response. Your code needs to interpret a 404 as 'this number is not registered' rather than a server error. Vatly normalizes this into a consistent response with valid: false.
Can I validate Northern Ireland VAT numbers?
Northern Ireland uses the XI prefix and is validated through VIES (not HMRC), since Northern Ireland remains in the EU's single market for goods. Vatly handles XI-prefixed numbers automatically, routing them to VIES.