# Stripe EU VAT ID verification: getting the answer before payment

Source: https://veriport.io/guides/stripe-eu-vat-id-verification (published 2026-11-12)

Stripe verifies an `eu_vat` tax ID against VIES (and a `gb_vat` against HMRC) after you add it to a customer: asynchronously, reported by the `customer.tax_id.updated` event with a status of pending, verified, unverified or unavailable. In Checkout, the number is checked for format during the session, not for validity, and `checkout.session.completed` can arrive before the verification ends. Stripe Tax applies reverse charge when the format is right, whatever the government answer. If you want the VIES answer before you decide, check the number yourself first.

- Stripe verifies `eu_vat` IDs with VIES, retries during VIES downtime, and reports `verification.status` through `customer.tax_id.updated`.
- Status `unavailable` means you must verify manually, in Stripe’s words.
- Checkout: format only during the session; validity afterwards; guest customers get no verification result or event.
- Stripe documents no consultation number on the tax ID object.

## Check first, then create the customer

Collect the VAT number in your own step before Checkout (or before an invoice), check it, and only then create the customer with the tax ID. You know the answer at the moment you choose between reverse charge and charging VAT, and you keep the date and the consultation number with the customer. Stripe still runs its own verification afterwards; yours is the one dated at the moment of the sale.

```javascript
// Your own form collects the VAT number first; the Checkout Session then reuses it.
const API = "https://veriport.io/api/v1";

async function checkVat(number) {
  const res = await fetch(API + "/vat/validate?number=" + encodeURIComponent(number) +
    "&requester=" + encodeURIComponent(process.env.OWN_VAT_NUMBER), {
    headers: { Authorization: "Bearer " + process.env.VERIPORT_KEY },
  });
  const body = await res.json();
  if (res.status === 503) return { decision: "retry_or_charge_vat" }; // VIES down, nothing cached
  if (!res.ok) throw new Error(body.code);
  return { decision: body.valid ? "reverse_charge" : "charge_vat", evidence: {
    valid: body.valid, requestDate: body.requestDate, kind: body.source.kind,
    consultationNumber: body.consultationNumber ?? null,
  } };
}

// const r = await checkVat(form.vatNumber);
// if (r.decision === "reverse_charge") {
//   customer = await stripe.customers.create({ email, tax_id_data: [{ type: "eu_vat", value: form.vatNumber }],
//     metadata: { vat_checked_on: r.evidence.requestDate, vies_consultation: r.evidence.consultationNumber ?? "" } });
// }
```

## What to keep

Customer metadata is enough for the date and the consultation number; with `record=true` on a paid tier the check is also kept on your Veriport account.

| Field | Why |
|---|---|
| `valid` | The VIES answer for the number on the day asked. |
| `requestDate`, `source.checkedAt` | When VIES answered (live) or when the cached answer was obtained. |
| `source.kind`, `source.stale` | `live` or `cache`; `stale: true` when the member state was down and a dated earlier answer was served. |
| `consultationNumber` | The Commission’s reference for this check, when you sent `requester` (your own VAT number) on a paid tier. |
| `name`, `address` | What the member state publishes; Germany and a few others publish neither. |

## Questions

### Is Stripe’s verification wrong?

No. It is asynchronous by design and retries through VIES outages. The question is timing: whether you need the answer before the payment, and a dated record of it, or whether the format check at payment is enough for your business.

### What about UK VAT numbers?

Stripe verifies `gb_vat` with HMRC. Veriport checks EU numbers on VIES and Northern Ireland (XI) numbers; Great Britain numbers are not on VIES.

## Read next

- [Validate EU VAT numbers in Node, Python and PHP](https://veriport.io/guides/validate-eu-vat-number-node-python-php)
- [EU VAT rates for digital services](https://veriport.io/guides/eu-vat-rates-digital-services-by-country)
- [Reference: GET /vat/validate](https://veriport.io/docs/vat-validation)

## Sources

- Stripe: customer tax IDs (eu_vat verified with VIES, asynchronous, customer.tax_id.updated, pending / verified / unverified / unavailable) — https://docs.stripe.com/billing/customer/tax-ids (2026-11-12)
- Stripe Checkout: collect tax IDs (format checked during the session; validity verified after) — https://docs.stripe.com/tax/checkout/tax-ids (2026-11-12)
- VIES on-the-Web endpoint: OpenAPI contract (POST /check-vat-number, GET /check-status; requester fields for the consultation number) — https://ec.europa.eu/assets/taxud/vow-information/swagger_publicVAT.yaml (2026-11-12)
