Skip to content

Tax-ID validation

Tax-ID validation

Reverse-charge zero-rating legally hinges on a validated business tax ID, so the engine validates it before treating a cross-border B2B supply as reverse-charge. The VatIdValidator contract does this, routing to the authoritative registry per country:

  • EU → VIES (ViesValidator) — returns a consultation reference (proof).
  • UK → HMRC "Check a UK VAT number" (HmrcVatValidator).
  • Australia → ABN Lookup (AbnLookupValidator, needs a GUID).
use Cbox\Tax\Contracts\VatIdValidator;
use Cbox\Geo\ValueObjects\CountryCode;

$result = app(VatIdValidator::class)->validate(new CountryCode('DE'), 'DE123456789');

$result->permitsReverseCharge();   // true only when conclusively valid
$result->consultationReference;    // proof-of-check id, record for audit

Feed permitsReverseCharge() into the customerTaxIdValidated flag on a TaxQuery.

Fail-safe by design

VatIdValidation carries a conclusive flag. When the service is unreachable or cannot determine validity, the result is inconclusivepermitsReverseCharge() is false, so the supply is taxed rather than wrongly zero-rated. A transport error never throws and never reads as "valid".

Configuration

VIES and HMRC are bound out of the box. To enable Australian ABN validation, set an ABN Lookup GUID:

// config/tax.php  (or .env: ABN_LOOKUP_GUID=...)
'vat_id' => ['abn_guid' => env('ABN_LOOKUP_GUID')],

Bind your own VatIdValidator (or add validators to the dispatcher) for other countries. Use Cbox\Tax\Testing\FakeVatIdValidator in tests — no network.

The adapters implement each service's documented request/response shape; verify against the live API (and provision production credentials) before relying on them.