If you sell B2B into the EU, two identifiers decide whether your invoice and your customs filing are right: the customer's VAT number (for reverse-charge invoicing) and their EORI number (for imports/exports). Both can be checked against official registries — for free — but the official APIs have real gotchas that silently produce wrong answers if you treat them naively. Here's how they actually behave, based on running validations against them in production.
The authoritative source is the EU's VIES service. Its REST endpoint looks like:
``` GET https://ec.europa.eu/taxation_customs/vies/rest-api/ms/{COUNTRY}/vat/{NUMBER} ```
A registered number returns `isValid: true` plus, for most member states, the registered trader's name and address — which is worth logging as evidence that you checked, because EU tax authorities can hold you liable for reverse-charging an unregistered buyer.
The gotchas:
"invalid" for every number and looks like it works (it "correctly" rejects garbage).
system. When one is down, the response still says `isValid: false` — but with `userError: MS_UNAVAILABLE`. If you don't check `userError`, a legitimate customer fails validation whenever their country's registry is having a bad hour (Germany's regularly does). Treat `MS_UNAVAILABLE`, `TIMEOUT`, and friends as "no answer, retry later", never as "invalid".
rather than storing literal dashes.
only ("IE6388047V" style).
EORI numbers are checked against the EU customs EOS database. There's no REST endpoint — it's a SOAP service:
``` POST https://ec.europa.eu/taxation_customs/dds2/eos/validation/services/validation ```
with a `validateEORI` envelope. `status: 0` means valid, and for many operators you get the registered company name back. The gotchas: it rate-limits aggressively if you call it in quick succession (space your calls), it periodically resets connections (retry with backoff, don't fail hard), and names come back XML-escaped (`&` in every "GmbH & Co. KG" — unescape before display).
Some identifiers validate offline, instantly, with pure math: IBAN (ISO 7064 mod-97 over the rearranged string), US ABA routing numbers (weighted digit checksum), and GTIN/UPC/EAN barcodes (check digit). Doing these locally before any registry call catches most typos for free.
We run these validations as a hosted MCP server that any AI agent (Claude, Cursor, Cline, or anything MCP-compatible) can call directly: live VIES and EORI lookups with the outage semantics handled correctly, DNS/MX email-domain checks, plus the offline checksum validators and EU VAT rates by date. The checksum and rate tools are free with no signup; the live registry lookups use a one-time key. Config is one line:
```json { "mcpServers": { "commerce-validators": { "url": "https://mcp.scienceswarm.org/mcp" } } } ```
It's open source (MIT) if you'd rather self-host — every tool is free and ungated that way.