VIES returns HTTP 200 when it's down, and I charged the wrong VAT because of it
When a German or French enterprise buyer enters a valid VAT number at checkout, they expect a 0% intra-community reverse-charge invoice once cross-border B2B supply conditions (sellerCountry !== buyerCountry) are met.
What caught me off guard is how the European Commission's VIES REST API (POST /taxation_customs/vies/rest-api/check-vat-number) behaves when a national tax registry is overloaded or unreachable: VIES returns HTTP 200 OK with actionSucceed: false and errorWrappers in the JSON body (or valid: false with userError in normalized adapters).
If your checkout code checks res.ok and then checks !body.valid before inspecting actionSucceed and errorWrappers, you treat a government database outage as an unregistered tax ID—and falsely charge your B2B customer 17%–27% VAT.
1. The HTTP 200 OK soft-failure payload
Here is the structure returned by the VIES REST endpoint (POST https://ec.europa.eu/taxation_customs/vies/rest-api/check-vat-number) on an HTTP 200 OK error wrapper response:
{
"actionSucceed": false,
"errorWrappers": [
{
"error": "MS_MAX_CONCURRENT_REQ"
}
]
}
Because the HTTP status is 200, standard HTTP retry middleware never triggers. And because body.valid is omitted (undefined) when actionSucceed is false (or mapped to valid: false alongside userError in adapter layers), any parser that checks !body.valid before inspecting transient outage codes in errorWrappers[] (MS_MAX_CONCURRENT_REQ, MS_UNAVAILABLE, SERVICE_UNAVAILABLE, GLOBAL_MAX_CONCURRENT_REQ, TIMEOUT—as opposed to permanent input errors like INVALID_INPUT or INVALID_REQUESTER_INFO) silently misclassifies a registry outage as an invalid VAT registration.
2. Prefix traps across 27 EU member states + XI
Before an order ever reaches VIES, raw checkout input across 27 EU member states plus Northern Ireland (XI for cross-border B2B goods under the Windsor Framework — 28 VAT prefixes) creates a second wave of false rejections:
- Greece (
GRvs.EL): ISO-3166 usesGRfor Greece, and billing forms emitGR. VIES strictly requires theELprefix—sendingGR123456789returnserrorWrappers: [{ "error": "INVALID_INPUT" }]unless normalized toEL123456789. - Northern Ireland (
XI): Under the Windsor Framework, Northern Ireland B2B goods transactions use theXIprefix rather thanGB. TreatingXIas post-Brexit UK (GB) strips valid intra-community reverse-charge treatment for goods. - Formatting noise & country syntax rules: Buyers paste spaces, dots, hyphens, and local tax office suffixes that must be stripped and validated against the 28 VAT prefix syntax rules before spending a network call.
| Checkout VAT Scenario | Naive VIES Integration | Financial / Tax Impact | RevClamp Circuit-Breaker Action |
|---|---|---|---|
valid: true Cross-Border (DE → FR) |
Applies 0% without consultation ID |
Missing consultation reference for tax audit | Approves 0% reverse-charge & archives SHA-256 consultation digest |
HTTP 200 + MS_MAX_CONCURRENT_REQ |
Treats !body.valid as unregistered VAT |
Falsely charges 17%–27% VAT; cart abandonment | Trips per-country breaker & queues PENDING_ASYNC_RETRY (up to 4 attempts) |
Greece ISO GR123456789 Input |
Sends GR prefix directly to VIES |
Rejected by VIES with INVALID_INPUT |
Auto-normalizes GR → EL (EL123456789) prior to VIES lookup |
Northern Ireland XI123456789 Goods |
Rejects XI as post-Brexit GB |
Strips valid Windsor Framework zero-rating | Admits XI prefix under 28-prefix syntax & VIES registry rules |
valid: false + Empty errorWrappers |
Blindly finalizes checkout or crashes | Uncollected VAT liability or lost B2B order | Places order in HOLD_INVALID_VAT (vat_audit:invalid_vat_id) for review |
3. Separating checkout admission from registry verification
My first instinct when seeing MS_MAX_CONCURRENT_REQ was to retry the request synchronously during checkout. That backfired immediately: holding a checkout request open while a national tax server times out causes buyer drop-off, and retrying immediately adds load to a member state that is already rate-limiting concurrent connections.
A production B2B VAT pipeline separates checkout admission from registry verification across three states:
- Verified Active (
valid: true+ cross-border B2B supply): An active VIES consultation (requestIdentifier/consultationNumber) is a necessary condition alongsidesellerCountry !== buyerCountryfor0%cross-border reverse-charge; archive the consultation timestamp, requester/buyer VAT IDs, and SHA-256 response digest (VERIFIED_ZERO_RATED, orVERIFIED_MISSING_CONSULTATION_IDhold if the consultation ID is absent). - Member-State Soft Failure (transient
errorWrapperspresent): Never charge penalty VAT and never block checkout. Place the order inPENDING_ASYNC_RETRY(vat_audit:pending_vies_retry), trip a per-member-state circuit breaker (so aDEslowdown never delaysFRorNLbuyers), and schedule bounded exponential-backoff retries (60s * 2^(attempt-1), up to 4 total attempts before escalating toHOLD_MANUAL_REVIEW_RETRY_EXHAUSTED). - Truly Invalid (
valid: falsewith emptyerrorWrappers, or permanent errors): When a VAT number is unregistered (valid: falsewith emptyerrorWrappers) or fails permanent validation (INVALID_INPUT,VAT_BLOCKED, or seller requester configuration errorINVALID_REQUESTER_INFO), place the order inHOLD_INVALID_VAT(vat_audit:invalid_vat_id) so finance can request a valid VAT ID, fix requester credentials, or collect standard domestic/destination VAT.