EU VAT and WooCommerce: How to Handle B2B Reverse Charge
If you're an EU-based seller shipping to other EU businesses, VAT is one of the most misunderstood areas of WooCommerce compliance. The rule in one sentence:
For B2B cross-border sales inside the EU, the seller doesn't charge VAT. The buyer "reverse charges" themselves and self-accounts for it.
Sounds simple. In practice you need to: validate the buyer's VAT number in real time, conditionally zero-rate the order, emit an invoice with a specific legal reference, and report the transaction to your own tax authority each quarter. WooCommerce handles approximately zero of this natively.
This guide covers the full flow: when reverse charge applies, how to validate VAT numbers, how to configure WooCommerce, invoicing requirements, and what to report to whom.
When does reverse charge apply?
Three conditions must all be true:
- You're VAT-registered in an EU country (the "seller side")
- The buyer is VAT-registered in a different EU country (with a valid VAT number)
- The transaction is cross-border within the EU (not domestic)
If any condition fails, different rules apply:
| Scenario | VAT treatment |
|---|---|
| Seller EU, Buyer EU same country | Charge local VAT (no reverse charge) |
| Seller EU, Buyer EU different country, valid VAT | Reverse charge — no VAT charged |
| Seller EU, Buyer EU different country, no VAT | Charge VAT at buyer's country rate (B2C OSS) |
| Seller EU, Buyer non-EU | Usually zero-rated (export) |
| Seller non-EU, Buyer EU | Buyer pays import VAT (not your problem) |
Reverse charge is the second row. The others have their own rules that aren't what this guide covers.
Step 1: Collect and validate the VAT number
At checkout, you need a field for the buyer's VAT number. When they submit it, you need to validate it against VIES — the EU VAT Information Exchange System.
VIES is a service run by the European Commission at ec.europa.eu/taxation_customs/vies/. It returns whether a given VAT number is valid (and registered for cross-border trade) in its country of issue.
Validation signals
- Valid + name matches: proceed. This business is registered, the number is real.
- Valid + name mismatch: flag for review. The number exists but the name on file differs from what the buyer entered.
- Invalid: reject. Number is fake or typo'd.
- VIES temporarily unavailable: this happens. You need a fallback — either block checkout, or accept the number and validate asynchronously.
Doing it yourself
You can call VIES directly via SOAP:
function validate_vat_vies( $country_code, $vat_number ) {
try {
$client = new SoapClient( 'https://ec.europa.eu/taxation_customs/vies/services/checkVatService.wsdl' );
$result = $client->checkVat( [
'countryCode' => $country_code,
'vatNumber' => $vat_number,
]);
return (bool) $result->valid;
} catch ( SoapFault $e ) {
// VIES temporarily unavailable — decide your fallback behavior
return null;
}
}
Cache aggressively. VIES is slow and rate-limited. A valid result for a given number doesn't need re-validation on every page load — cache for a few hours to a day.
Using a plugin
Most stores shouldn't roll this. The maintenance burden (SOAP, rate limits, VIES outages, XML parsing quirks) isn't worth reinventing. Recommended:
- EU VAT Assistant (Aelia) — free, maintained, widely deployed. Adds the checkout field, validates via VIES, handles the tax rules below. Use this as the default.
- WooCommerce EU VAT Number — the official-ish WooCommerce.com option. Simpler feature set.
- EU / UK VAT Compliance (Aelia) — premium sibling of the Assistant with additional features like currency exchange rate logging and detailed reports.
Step 2: Zero-rate the order when reverse charge applies
Once you've validated the VAT number, you need to tell WooCommerce: "don't charge VAT on this order."
The mechanism is the same is_vat_exempt flag we've covered for general tax exemption:
add_action( 'woocommerce_checkout_update_order_review', function () {
$vat = WC()->session->get( 'vat_number_validated' );
if ( $vat ) {
WC()->customer->set_is_vat_exempt( true );
} else {
WC()->customer->set_is_vat_exempt( false );
}
});
If you're using EU VAT Assistant, this happens automatically based on its validation logic. If you're using our Tax Exempt plugin for manual exemptions (resellers, non-profits), it composes cleanly — both set the same underlying flag.
The order must still reach your tax authority
Reverse charge doesn't mean "no tax anywhere." It means the buyer pays the tax in their country instead of you collecting it. You still have to report the transaction to your own tax authority (see OSS and EC Sales List below). So: the order is zero-rated at checkout, but you need to know later who was reverse-charged, for how much, and where.
WooCommerce stores this. Make sure your plugin tags reverse-charged orders clearly — EU VAT Assistant adds order meta flags like _vat_rc = yes that you can query later.
Step 3: Emit a reverse-charge invoice
EU law requires the invoice to include a specific note indicating reverse charge applies. The exact wording varies by country, but common versions:
VAT reverse charge — Art. 196 Directive 2006/112/EC
Inversione contabile — Art. 7-ter D.P.R. 633/1972 (Italy)
Reverse charge (UK — though post-Brexit this is about EU-UK trade, not intra-EU)
Your invoice PDF must include:
- Seller's VAT number (yours)
- Buyer's VAT number (validated)
- Line items with 0% VAT (not "no VAT" — explicitly zero-rated)
- The reverse charge note
Most PDF invoice plugins support this if configured. The WooCommerce PDF Invoices & Packing Slips plugin + the EU VAT Assistant integrate out of the box; otherwise you'll customize the template.
Step 4: Report the transaction
This is the part most developers forget. Reverse-charged sales don't escape your tax obligations — they just change which obligation.
Inside the EU: EC Sales List / Intrastat
Most EU countries require you to file an EC Sales List (or the equivalent) with a periodic summary of B2B sales to other EU countries. The list contains: buyer's VAT number, country, and total value of sales during the period. It's usually monthly or quarterly.
Your WooCommerce reports probably don't emit this directly. You'll export order data (CSV or via REST API) and prepare the filing either yourself or via an accountant.
OSS (One-Stop Shop)
If you do B2C cross-border EU sales, you should be registered for OSS — the quarterly simplified VAT return for distance sales across the EU. OSS is not for reverse charge (which is B2B), but many stores do both, so you end up filing both:
- EC Sales List / Intrastat for B2B reverse-charged sales
- OSS return for B2C cross-border sales
Some plugins (like Aelia's premium tier) generate both. Others don't. Ask your accountant.
WooCommerce tax setup for EU B2B
Under WooCommerce → Settings → Tax, configure:
- Prices entered with tax: depends on your country convention, usually "Yes, I will enter prices inclusive of tax" in the EU
- Calculate tax based on: "Customer shipping address"
- Shipping tax class: "Standard"
- Rounding: "Round tax at subtotal level, instead of rounding per line"
- Additional tax classes: usually just Standard + Zero Rate + Reduced Rate
For each EU country you ship to, set up VAT rates in Standard rates. A row per country. Set the correct rate per country (19% Germany, 20% France, 21% Netherlands, etc.). Your VAT plugin will handle zero-rating for reverse charge; you don't set that manually.
If you sell digital goods, you also need to configure VAT MOSS / OSS rates for B2C — that's a separate topic.
Post-Brexit note on UK
If you're EU selling to UK businesses, reverse charge doesn't apply — UK left the EU, so EU-UK trade is now import/export. For UK buyers:
- Under £135: you charge UK VAT and register for UK VAT
- Over £135: buyer handles import VAT (not your problem)
Don't try to treat UK as an EU reverse charge country. Your VIES lookup will fail (UK is no longer in VIES for intra-EU trade) and any invoice you emit with "EU reverse charge" will be wrong.
EU VAT Assistant and similar plugins handle this correctly as of early 2026.
Common mistakes
Not validating VAT numbers. Accepting any string the customer types in is a compliance failure waiting to happen. If an auditor finds a customer who was reverse-charged with an invalid VAT number, you owe the VAT yourself plus penalties.
Validating only the format. VAT numbers have country-specific format rules (IT numbers are 11 digits, DE are 9, etc.). Format validation catches typos. VIES validation confirms the number is actually registered. Do both.
Hard-failing when VIES is down. VIES has outages. If your checkout rejects every VAT number during an outage, you lose sales unnecessarily. Better: validate asynchronously, accept the order, flag it for manual review if VIES hasn't confirmed within an hour.
Forgetting the EC Sales List. Your auditor asks for it once a year. If you haven't been filing, the retroactive filing + fines are painful.
Treating all EU countries the same. Each country has slightly different invoicing requirements, language preferences, and report formats. A good VAT plugin handles this; home-brewed logic usually doesn't.
The short version
- Reverse charge applies only to cross-border EU B2B with a valid VAT number
- Validate VAT numbers via VIES — don't roll your own for production
- Zero-rate the order when reverse charge applies (set
is_vat_exempt = true) - Emit invoices with the reverse charge legal reference
- File EC Sales List / Intrastat periodically — don't forget this step
- Use EU VAT Assistant or similar for the heavy lifting; don't try to DIY