Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Vat Bundle Laravel Package

sparkling/vat-bundle

sparkling/vat-bundle is a Symfony bundle for validating EU VAT numbers through the VIES service, with ready-to-use validators and services that make it easy to add VAT checks to checkout, onboarding, or other PHP application workflows.

View on GitHub
Deep Wiki
Context7

Getting Started

The first thing to understand is the mismatch: sparkling/vat-bundle is a Symfony 2 bundle (archived since 2018), and its only real job is validating European VAT numbers against VIES (the EU's VAT Information Exchange System). There is no Laravel service provider, no facade, and nothing that will auto-discover. Treat it as a small library you wire up yourself.

Minimal steps:

  1. Install and check compatibility first — this is the make-or-break step:
    composer require sparkling/vat-bundle
    
    Run it against your PHP version before committing. The package predates PHP 7.2+, so expect deprecation noise or a hard failure on PHP 8. If it won't install, stop here and use a maintained alternative (see Gotchas) — do not vendor-patch it in.
  2. Read two files first: the validator constraint (Ruudk\VATBundle\Validator\Constraints\VATNumber) and its validator class. They tell you the exact contract — what input it expects (a normalized number vs. a country code + number pair) and what it considers "valid."
  3. Locate the VIES client the bundle ships/delegates to. That client is the only piece worth reusing in a Laravel app; the Symfony validator plumbing is not.
  4. First use case: validating the VAT number field on a B2B registration form or a business checkout step, i.e. "is this company VAT-registered and can we zero-rate the invoice?"

A pragmatic Laravel wiring if you keep the bundle:

// app/Services/Vat/VatValidator.php
use Ruudk\VATBundle\Validator\Constraints\VATNumber;

class VatValidator
{
    public function isValid(string $number, string $country): bool
    {
        $constraint = new VATNumber(['country' => $country]);
        // Instantiate the bundle's validator with its dependencies manually,
        // or call the underlying VIES client directly.
    }
}

If instantiation is painful (it usually is for a Symfony 2 bundle), skip the constraint entirely and reach into the client class — that is the pragmatic day-to-day move.

Implementation Patterns

1. Constraint-on-entity (native Symfony style). If you are genuinely on an old Symfony app, this is the intended usage — annotate the property and let the validator run:

use Ruudk\VATBundle\Validator\Constraints as VatAssert;

class Company
{
    /** @VatAssert\VATNumber */
    protected $vatNumber;
}

2. Adapter into Laravel validation. The most useful pattern: wrap the bundle in a custom rule so the rest of your app never sees it.

class ValidVatNumber implements ValidationRule
{
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
        [$country, $number] = $this->split($value); // "NL123456789B01" -> NL + rest
        if (! app(VatValidator::class)->isValid($number, $country)) {
            $fail('The VAT number could not be verified with VIES.');
        }
    }
}

Use it as ['required', new ValidVatNumber] on the billing form.

3. Cache aggressively, keyed by normalized number. VIES is a slow, rate-limited SOAP service. Every check should go through:

return Cache::remember("vies:{$country}:{$number}", now()->addDay(), function () use (...) {
    return $this->client->check($number, $country);
});

Cache positive and negative results, but give negatives a shorter TTL (an hour vs. a day) — a number can become valid after registration.

4. Async / soft-validation at checkout. Do not block a checkout on a live VIES call. Pattern: accept the order, queue a VerifyVatNumber job, and mark the invoice as "VAT pending" until verified. This avoids losing sales to VIES downtime.

5. Normalize before validating. EU VAT numbers arrive with spaces, dots, and dashes. Strip everything non-alphanumeric and uppercase before hitting the client, and store the normalized form alongside the raw input.

6. Test with a fake client. Bind a stub implementation of the client in your test container so tests never touch the network; assert the validator rejects invalid/malformed input and that caching works.

Gotchas and Tips

  • It is archived and unmaintained. No PHP 8 fixes, no security patches, and the dependency tree is likely conflicted. Audit composer why after install, and budget a migration path away from it.
  • VIES is unreliable by nature. It has scheduled maintenance windows and frequent SOAP timeouts. Always set a short timeout (2–5s), catch SoapFault, and treat errors as "unknown" — never as "invalid." Rejecting a legitimate business because VIES was down is a real support-ticket generator.
  • Don't trust the boolean alone. VIES returns validity plus the registered company name and address. Capture and persist that snapshot; it is your audit trail for zero-rated invoices and is what tax authorities expect you to show.
  • Not every valid VAT number is VIES-checkable. Some EU countries (and non-EU countries with VAT schemes) don't respond, and certain registrations are exempt. Design your rule to return a tri-state: valid / invalid / unverifiable, and let the user proceed on unverifiable with a flagged record.
  • North Macedonia/GB and post-Brexit numbers are a classic trap: GB numbers are no longer in VIES after Brexit. Don't hardcode the country list inside the old bundle — derive it from config so you can update without forking.
  • The VATNumber constraint name collides conceptually with Symfony's own VatNumber/other packages. Be explicit with aliases when annotating.
  • No configuration is exposed for the endpoint. If you need to point at a mock server or a regional VIES mirror, you will have to subclass or decorate the client — capture the client in your own service so this is a one-line swap.
  • Debugging tip: log the raw SOAP request/response (redact nothing sensitive here — the VAT number is the input). Most "it says invalid but it's valid" bugs are a normalization mismatch: wrong country prefix, lowercase letters, or the country code stripped twice.
  • Migration advice for a Laravel shop: the bundle's value is essentially one function call. Reproduce it with a small dragonbe/vies-style client wrapped in your own VatValidator service; you'll get PHP 8 support, testability, and no dead-bundle risk — usually in under an hour.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo