PHPackages                             byte8/module-vat-validator - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Validation &amp; Sanitization](/categories/validation)
4. /
5. byte8/module-vat-validator

ActiveMagento2-module[Validation &amp; Sanitization](/categories/validation)

byte8/module-vat-validator
==========================

EU VIES + UK HMRC VAT number validator for Magento 2 — validates B2B buyers at registration and checkout and auto-applies zero-tax customer groups.

1.1.0(2w ago)021MITPHPPHP ^8.1|^8.2|^8.3|^8.4|^8.5CI passing

Since Apr 28Pushed 2w agoCompare

[ Source](https://github.com/byte8io/magento-vat-validator)[ Packagist](https://packagist.org/packages/byte8/module-vat-validator)[ Docs](https://byte8.io/integrations/vat-validator)[ RSS](/packages/byte8-module-vat-validator/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (11)Versions (4)Used By (1)

Byte8\_VatValidator — EU VIES + UK HMRC + Swiss UID VAT Number Validator
========================================================================

[](#byte8_vatvalidator--eu-vies--uk-hmrc--swiss-uid-vat-number-validator)

A lightweight Magento 2 module that validates B2B buyers' VAT numbers against the **EU VIES** REST API, the **UK HMRC** public lookup endpoint, and the **Swiss UID-Register** (Bundesamt für Statistik) — at customer registration and again at checkout — and automatically moves validated customers into a configurable "Zero Tax" customer group so the right tax rules fire immediately.

Why merchants install it
------------------------

[](#why-merchants-install-it)

- Magento's native VAT validation hits the deprecated VIES SOAP endpoint and offers no UK coverage post-Brexit.
- This module uses the current REST endpoints, works for all 27 EU member states plus Northern Ireland (`XI`) and Great Britain (`GB`), and produces a typed, cache-aware validation result.
- Validated B2B customers are auto-assigned to your chosen customer group, so any existing tax rule driven by customer group (reverse charge, 0% for intra-EU B2B, etc.) just works.

Features
--------

[](#features)

- EU VIES REST validation (no SOAP, no `php-soap` extension required)
- UK HMRC "Check a UK VAT number" v2.0 lookup (application-restricted: server token from HMRC Developer Hub required)
- Swiss UID-Register validation via hand-rolled SOAP envelope (no `ext-soap` dependency); returns `valid` only when the organisation is active **and** VAT-registered (MWST)
- Pluggable: disable any upstream independently
- Auto-assign customer group by outcome (domestic / intra-EU valid / invalid)
- **Non-blocking checkout path**: the quote-address observer reads from the persisted log (TTL-bounded) and enqueues an asynchronous `byte8.vat.revalidate`job when the cache is stale. Customers never wait on VIES/HMRC during checkout.
- Per-request in-memory cache so one checkout doesn't hit VIES 5 times
- Two REST endpoints:
    - `GET /rest/V1/byte8-vat-validator/validate/:countryCode/:vatNumber` — *always synchronous*, hits the upstream. Use from the address-form path.
    - `GET /rest/V1/byte8-vat-validator/lookup/:countryCode/:vatNumber` — *cache-aware*. Returns the latest fresh log entry within the configured TTL; otherwise returns `skipped` and queues an async revalidation. Use from latency-sensitive paths.
- **DB-backed validation log** with admin grid, CSV / Excel XML export, configurable retention (default 10 years per §147 AO) and a nightly prune cron — built for German Finanzamt audits but useful for any merchant
- **Event hook** `byte8_vat_validator_validated` so other modules (e.g. Byte8 Ledger) can subscribe to every validation
- Dedicated log file at `var/log/vat_validator.log` for ops debugging
- CLI: `bin/magento byte8:vat:validate GB123456789`

Companion modules
-----------------

[](#companion-modules)

### Hyvä storefront support

[](#hyvä-storefront-support)

Running a Hyvä-themed storefront? Install **[byte8/module-vat-validator-hyva](https://github.com/byte8io/magento-vat-validator-hyva)**for a live, debounced VAT-validation indicator on the registration and address forms — green / red badge appears under the VAT input as the customer types, no extra JS dependencies (Alpine + Tailwind only).

```
composer require byte8/module-vat-validator-hyva
```

Requirements
------------

[](#requirements)

- Magento 2.4.x
- PHP 8.1+

Installation
------------

[](#installation)

```
composer require byte8/module-vat-validator
bin/magento module:enable Byte8_VatValidator
bin/magento setup:upgrade
bin/magento cache:flush
```

### Run the queue consumer

[](#run-the-queue-consumer)

The checkout path is non-blocking: when the persisted result is stale or missing, the observer publishes to `byte8.vat.revalidate` instead of calling the upstream synchronously. You must run the consumer for those jobs to drain (otherwise the audit log won't refresh):

```
bin/magento queue:consumers:start byte8.vat.revalidate
```

In production, supervise this under your existing consumer manager (e.g. `bin/magento queue:consumers:list`, systemd, or `cron_run` mode). The default Magento DB-backed queue is used — no AMQP / RabbitMQ broker is required, but you can switch the connection in `etc/queue_topology.xml`if you already run one.

Configuration
-------------

[](#configuration)

Navigate to **Stores &gt; Configuration &gt; Byte8 &gt; VAT Number Validator**.

### General

[](#general)

FieldDescriptionEnable VAT ValidatorMaster switchValidate on Customer SaveRun synchronous validation when a customer or address is saved (the customer is waiting on the form, so a synchronous call is appropriate)Validate on CheckoutApply cached / async-revalidated VAT result during quote-address save (non-blocking)Request Timeout (seconds)Hard response timeout on upstream calls. Default 2sConnect Timeout (seconds)TCP/TLS connect timeout. Default 1s — fails fast on unreachable upstreamsResult Cache TTL (hours)How long a persisted validation outcome is reused before async revalidation is triggered. Default 24hRequester Country CodeYour 2-letter ISO code (e.g. `GB`, `DE`) — sent to VIESRequester VAT NumberYour own VAT number — included in VIES calls for a consultation number### EU VIES

[](#eu-vies)

Toggle + endpoint override. Defaults to the current EC REST endpoint.

### UK HMRC

[](#uk-hmrc)

FieldDescriptionValidate UK numbers via HMRCToggle for the HMRC clientHMRC Lookup Endpointv2.0 endpoint override; leave default unless HMRC publishes a new pathHMRC OAuth Token EndpointOAuth 2.0 `/oauth/token` URL. Default `https://api.service.hmrc.gov.uk/oauth/token`HMRC Client ID**Required.** OAuth client identifier from your HMRC applicationHMRC Client Secret**Required.** OAuth client secret. Stored encrypted via Magento's `Encrypted` backend model#### Each merchant must register their own HMRC application

[](#each-merchant-must-register-their-own-hmrc-application)

The "Check a UK VAT number" API v2.0 is *application-restricted* and uses OAuth 2.0 client-credentials. **Do not share credentials between sites or re-use a vendor's credentials** — HMRC ties consultation references and rate limits to the calling application, so every audit-log entry must trace back to the merchant's own HMRC enrolment.

Setup steps for each merchant:

1. Sign up at [developer.service.hmrc.gov.uk](https://developer.service.hmrc.gov.uk).
2. Create an application (production *and* sandbox if you want to test without hitting live data).
3. Subscribe the application to **"Check a UK VAT number"** v2.0.
4. Copy the application's *Client ID* and *Client Secret* into the admin fields above. The module uses them to fetch a short-lived bearer token via OAuth `client_credentials`; tokens are cached in Magento's default cache for ~`expires_in − 60s` so checkout requests never wait on the token endpoint.

### Customer Group Mapping

[](#customer-group-mapping)

FieldApplied WhenAuto-Assign Customer GroupMaster switch for group assignmentDomestic GroupVAT valid AND buyer country == requester countryIntra-EU / UK Valid GroupVAT valid AND buyer country != requester country (zero-tax / reverse-charge)Invalid GroupVAT validation returned "invalid"When VIES or HMRC is **unavailable** (HTTP 5xx, timeout, malformed response) the customer's current group is preserved — we never downgrade a customer based on a flaky upstream.

### Validation Log (DACH compliance: §18 / §147 AO)

[](#validation-log-dach-compliance-18--147-ao)

FieldDescriptionPersist Validations to DBMaster switch — when Yes, every `valid` / `invalid` outcome is written to `byte8_vat_validator_log`. Transient `unavailable` errors are NOT persisted, keeping the audit log clean.Retention (years)Default 10 — matches §147 AO. A nightly cron (`byte8_vat_validator_prune_log` at 03:17) deletes anything older.View entries under **Stores → Byte8 → VAT Validation Log**. The grid supports filters (date range, country, status, source, customer email, qualified-confirmation reference) and CSV / Excel XML export — the export button is gated by a separate `Byte8_VatValidator::log_export` ACL so you can grant view access without granting export.

Each row stores: customer id + email at time of check, store id, country, VAT number, status, source (`vies` / `hmrc`), the upstream `requestIdentifier` (your *qualifizierte Bestätigung* reference), the returned company name + address, and the raw request + response payloads for audit reconstruction.

REST endpoints
--------------

[](#rest-endpoints)

Two routes, with different latency/freshness trade-offs:

```
# Synchronous: hits HMRC/VIES/UID-CHE every time. Use for the address form.
curl https://yourshop.test/rest/V1/byte8-vat-validator/validate/GB/123456789

# Cache-aware: returns the latest fresh log entry within Result Cache TTL,
# otherwise queues an async revalidation and returns status=skipped.
curl https://yourshop.test/rest/V1/byte8-vat-validator/lookup/GB/123456789
```

Returns a JSON validation result:

```
{
  "country_code": "GB",
  "vat_number": "123456789",
  "status": "valid",
  "source": "hmrc",
  "name": "Acme Ltd",
  "address": "1 Main St, London, SW1A 1AA, GB",
  "request_identifier": "CONS-2026-1234"
}
```

Status is one of `valid`, `invalid`, `unavailable`, `skipped`.

CLI
---

[](#cli)

### Validate one number

[](#validate-one-number)

```
bin/magento byte8:vat:validate GB123456789      # UK / HMRC
bin/magento byte8:vat:validate DE123456789      # EU / VIES
bin/magento byte8:vat:validate CHE-123.456.789  # Switzerland / UID-Register
```

Exit code `0` on valid, `1` otherwise — handy in CI / smoke tests.

### Bulk re-validate every B2B customer

[](#bulk-re-validate-every-b2b-customer)

Useful right after install (back-fill validations for an existing customer base) or as a periodic clean-up to catch numbers that became invalid.

```
bin/magento byte8:vat:revalidate-all                       # everyone with a vat_id
bin/magento byte8:vat:revalidate-all --country=DE,AT       # DACH only
bin/magento byte8:vat:revalidate-all --since=2026-01-01    # addresses updated since
bin/magento byte8:vat:revalidate-all --limit=50            # spot-check
bin/magento byte8:vat:revalidate-all --dry-run             # list, don't call
```

Each result is persisted to `byte8_vat_validator_log` automatically (no special-case path — same event hook the live observers use). The command prints a per-row outcome and a final summary with valid / invalid / unavailable / skipped counts.

How the "Zero Tax" rule gets applied
------------------------------------

[](#how-the-zero-tax-rule-gets-applied)

This module does not edit tax rules directly. Instead:

1. Configure a customer group (e.g. "B2B EU Valid") with the tax class you want.
2. Add a Magento tax rule that maps that tax class to 0%.
3. Point the module's **Intra-EU / UK Valid Group** setting at the group above.

When validation succeeds during registration, the customer is moved into that group — and when it succeeds during checkout, the quote's customer group is updated in-flight so totals recalculate before the order is placed.

Logging
-------

[](#logging)

All validator activity is logged to `var/log/vat_validator.log`. In production, tail this file to monitor upstream availability and validation outcomes.

Upsell hook
-----------

[](#upsell-hook)

After install, merchants receive a follow-up email from Byte8 introducing **Byte8 Ledger**, which syncs validated B2B customers straight into **Sage** and **Xero**. Cross-sell copy lives in Byte8's email platform, not in this module.

Privacy &amp; GDPR
------------------

[](#privacy--gdpr)

This module processes and stores personal / business data — read this section before installing on a production store.

### What we send to third parties

[](#what-we-send-to-third-parties)

UpstreamData sentWhere it goesEU VIESThe buyer's country code, VAT number, and (if configured) your own country + VAT number as the requesterEC Directorate-General for Taxation and Customs Union (`ec.europa.eu`)UK HMRCThe buyer's VAT number, and (if your requester VAT is configured) your own VAT numberHM Revenue &amp; Customs (`api.service.hmrc.gov.uk`)Swiss UID-RegisterThe buyer's UID (CHE prefix + 9 digits)Bundesamt für Statistik (`uid-wse.admin.ch`)Both upstreams may return the buyer's company name and registered business address. We persist these in `byte8_vat_validator_log` only when the "Persist Validations to DB" setting is enabled.

### Lawful basis (GDPR Art. 6 / UK GDPR Art. 6)

[](#lawful-basis-gdpr-art-6--uk-gdpr-art-6)

- **Sending VAT numbers to VIES / HMRC:** Art. 6(1)(c) — *legal obligation*. EU and UK VAT law requires merchants to verify cross-border B2B VAT numbers before applying zero-rated / reverse-charge treatment.
- **Storing the validation log:** Art. 6(1)(c) — *legal obligation*. Specifically, German `§147 AO` mandates 10-year retention of records supporting tax treatment; equivalent obligations exist in most EU member states.

This means **you do not need consent** to use this module for B2B validation — it falls under your existing tax-compliance obligations. You **do** need to disclose the processing in your privacy policy. Suggested copy:

> We verify your VAT identification number against the European Commission's VIES database (and, for UK numbers, against HMRC) when you register or place an order, in order to apply the correct VAT treatment. The validation result, including any company name and address returned by VIES / HMRC, is retained for \[10\] years in line with our statutory tax-record obligations.

### Data subject rights

[](#data-subject-rights)

The validation log is keyed on `customer_id` (with `ON DELETE SET NULL`), so deleting a customer detaches their log entries but preserves the historical record for audit. If a data subject requests erasure under GDPR Art. 17, you'll need to weigh that against your Art. 17(3)(b) exemption for "compliance with a legal obligation". In most cases the tax-record obligation prevails — document this in your erasure-request response process.

### What we do NOT do

[](#what-we-do-not-do)

- We do not phone home. The module makes no calls to byte8.io or any Byte8 endpoint.
- We do not log to any third-party telemetry / APM service.
- We do not transmit the buyer's name, email, or address to VIES / HMRC — only the country code + VAT number.

License
-------

[](#license)

MIT — see [LICENSE.txt](LICENSE.txt).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance96

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 94.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~22 days

Total

2

Last Release

19d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/612c19aab21c48e9c7d11d11eab8863b9473743c6ab7335aeb5a1424129b46cc?d=identicon)[softcom](/maintainers/softcom)

---

Top Contributors

[![softcommerceltd](https://avatars.githubusercontent.com/u/6104757?v=4)](https://github.com/softcommerceltd "softcommerceltd (18 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

magentob2bvatmagento2taxviesmagento 2vat-validatorhmrcreverse-charge

### Embed Badge

![Health badge](/badges/byte8-module-vat-validator/health.svg)

```
[![Health](https://phpackages.com/badges/byte8-module-vat-validator/health.svg)](https://phpackages.com/packages/byte8-module-vat-validator)
```

###  Alternatives

[mollie/magento2

Mollie Payment Module for Magento 2

1131.8M12](/packages/mollie-magento2)[run-as-root/magento2-prometheus-exporter

Magento2 Prometheus Exporter

68353.9k](/packages/run-as-root-magento2-prometheus-exporter)[dotdigital/dotdigital-magento2-extension

Dotdigital for Magento 2

50390.4k20](/packages/dotdigital-dotdigital-magento2-extension)[loki/magento2-components

Core module for defining Alpine.js components with advanced AJAX features

1010.0k22](/packages/loki-magento2-components)[buckaroo/magento2

Buckaroo Magento 2 extension

32414.8k7](/packages/buckaroo-magento2)[mage-os/module-admin-activity-log

The Admin Activity extension makes it easy to track all admin activity with comprehensive audit logging.

293.3k](/packages/mage-os-module-admin-activity-log)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
