DEV Community

Cover image for I Built a VAT Number Validator API for 35 Countries - Day 3 of 21
Ruan Muller
Ruan Muller

Posted on

I Built a VAT Number Validator API for 35 Countries - Day 3 of 21

Day 3 of my 21-day API challenge is done.

Yesterday I built a Password Strength Scorer. Today I built a VAT Number Validator API - validate VAT numbers for 35 countries, get tax rates, currency info and EU membership status in one call.

If you missed the previous days:


The Problem

Every e-commerce platform selling to European businesses needs VAT validation. It sounds simple but it's surprisingly painful to build:

  • Every country has a different format
  • Germany is DE + 9 digits
  • France is FR + 2 alphanumeric + 9 digits
  • Netherlands is NL + 9 digits + B + 2 digits
  • And so on for 27 EU countries plus the UK, Norway, Switzerland and more

Most developers end up copying regex patterns from Stack Overflow and maintaining a messy country-by-country switch statement. I packaged all of that into a clean API.


What I Built

The VAT Number Validator API - send it a VAT number, get back full validation info.

Input:

{
  "vat_number": "DE123456789"
}
Enter fullscreen mode Exit fullscreen mode

Output:

{
  "success": true,
  "data": {
    "vat_number": "DE123456789",
    "country_code": "DE",
    "country": "Germany",
    "is_valid": true,
    "format_valid": true,
    "format_expected": "DE#########",
    "eu_member": true,
    "tax_info": {
      "standard_rate": 19,
      "reduced_rates": [7],
      "currency": "EUR"
    },
    "validation_note": "Format is valid"
  }
}
Enter fullscreen mode Exit fullscreen mode

And for an invalid number:

{
  "vat_number": "DE123",
  "is_valid": false,
  "validation_note": "Expected format: DE#########"
}
Enter fullscreen mode Exit fullscreen mode

The 6 Endpoints

Method Endpoint Description
GET /health Health check
POST /validate Validate a single VAT number
POST /validate/batch Validate up to 20 at once
GET /countries List all 35 supported countries
GET /countries/:code Get info for a specific country
POST /format Clean and normalize a VAT number

The /validate/batch endpoint is particularly useful for platforms doing bulk customer verification β€” validate an entire customer list in one API call instead of looping through one by one.


The Countries Database

The core of this API is a rules database with validation patterns for every supported country:

const VAT_RULES = {
  DE: {
    country:       "Germany",
    pattern:       /^DE\d{9}$/,
    format:        "DE#########",
    standard_rate: 19,
    reduced_rates: [7],
    currency:      "EUR",
    eu_member:     true,
  },
  ZA: {
    country:       "South Africa",
    pattern:       /^ZA4\d{9}$/,
    format:        "ZA4#########",
    standard_rate: 15,
    reduced_rates: [0],
    currency:      "ZAR",
    eu_member:     false,
  },
  // ... 33 more countries
};
Enter fullscreen mode Exit fullscreen mode

The validation is then a simple pattern match:

function validateFormat(vat) {
  const normalized = vat.toUpperCase().replace(/[\s\-\.]/g, "");
  const countryCode = normalized.slice(0, 2);
  const rule = VAT_RULES[countryCode];

  if (!rule) return { valid: false, reason: "Unknown country prefix" };

  return {
    valid:  rule.pattern.test(normalized),
    reason: rule.pattern.test(normalized) ? "Format is valid" : `Expected: ${rule.format}`,
  };
}
Enter fullscreen mode Exit fullscreen mode

Supported Countries

All 27 EU Members:
Austria, Belgium, Bulgaria, Cyprus, Czech Republic, Germany, Denmark, Estonia, Greece, Spain, Finland, France, Croatia, Hungary, Ireland, Italy, Lithuania, Luxembourg, Latvia, Malta, Netherlands, Poland, Portugal, Romania, Sweden, Slovenia, Slovakia

Plus 8 Non-EU Countries:
United Kingdom, Norway, Switzerland, South Africa, Australia, New Zealand, India, Singapore, Canada


Why I Included South Africa

I'm a developer from South Africa studying accounting. South African VAT runs at 15% and every local e-commerce business dealing with international customers needs this.

Most VAT APIs focus exclusively on EU countries and completely ignore the rest of the world. That's a gap worth filling.


The Batch Endpoint

The /validate/batch endpoint validates up to 20 VAT numbers at once and returns a summary:

{
  "summary": {
    "total": 4,
    "valid": 3,
    "invalid": 1,
    "eu_numbers": 2,
    "non_eu_numbers": 2
  }
}
Enter fullscreen mode Exit fullscreen mode

Useful for:

  • Validating customer lists during import
  • Auditing existing customer databases
  • B2B onboarding flows where you collect multiple VAT numbers

Tech Stack

  • Runtime: Node.js + Express
  • Hosting: Railway (free tier)
  • Marketplace: RapidAPI
  • Dependencies: express, cors, helmet, morgan, express-rate-limit

Zero paid APIs. Zero external calls. Pure in-memory validation β€” which means it's fast and costs almost nothing to run.


Try It

Live on RapidAPI - search VAT Number Validator or find me at Rapid Api.

Free tier: 10 requests/month. No credit card required.


What's Next

Day 4 tomorrow - Text Readability Scorer API.

Every content platform, SEO tool and email marketing app needs to know how readable their text is. Flesch-Kincaid score, grade level, reading time, passive voice percentage - all in one call.

Follow me here on dev.to to catch every day of the challenge. πŸ‡ΏπŸ‡¦


21 APIs in 21 days. Built in South Africa. Sold globally.

Top comments (0)