Tax & compliance
B2B VAT ID Validation & Tax Exemption
Indicative price, not an offer: $15-29/mo + per-validation fees (EUR 0.10-0.50/lookup)
Generated from docs/plan/paid/b2b-vat-id-validation-tax-exemption/PLAN.md in the AstroBaaS repository. Nothing described below is implemented — it is the written plan for it.
Paid module (EUR 15–29/mo plus per-lookup fees of EUR 0.10–0.50) that validates B2B customer VAT IDs in real time (VIES API, country-specific registries), marks customers as tax-exempt on valid ID, and stores exemption certificates. Prevents chargebacks when a B2B customer claims tax exemption without documentation.
The problem
B2B customers claim tax exemption by providing a VAT ID, but I cannot verify it. Accepting invalid IDs means I charge VAT I should not, then the customer disputes the charge. Failing to accept valid IDs means I lose deals. No way to store proof of exemption for audits.
What it does
- Real-time VAT ID validation via VIES (EU) and country-specific registries (Avalara, TaxJar, or manual databases)
- Validation happens at checkout or customer profile: merchant (or customer) enters VAT ID, system checks, and flags as ‘verified’ or ‘invalid’
- Valid IDs trigger tax exemption flag on the customer record; all future orders auto-apply 0% tax
- Validation result is cached for 24 hours (to avoid repeated API calls) but re-checked on demand
- Exemption certificate storage: system records the validation date, VAT ID, customer name, and validation source in an audit log
- Customer portal: B2B customers can view their VAT ID status and upload supplementary exemption documents (EU form OSS-1, country VAT cert, etc.)
- Admin tools: bulk VAT ID upload/validation (CSV), exemption status dashboard, validation history per customer
What it deliberately does NOT do
Each boundary carries its reason. A boundary without a reason gets crossed by the next person who reads this.
- No local/state tax (USA) validation — only VAT (reason: US sales tax has 10,000+ jurisdictions; that is a separate vertical)
- No automatic exemption certificate generation or e-signature — merchants upload documents manually (reason: legal certificates must be reviewed by a lawyer, not auto-generated)
- No VIES-specific rules or country-specific exemption workflows — same validation logic for all EU countries (reason: every country has edge cases; merchants in complex jurisdictions hire tax services)
Data model
Customer gains fields: vat_id (text), vat_id_verified (boolean), vat_id_verified_date (timestamp), vat_id_verified_source (string: ‘VIES’ | ‘Avalara’ | ‘manual’), tax_exempt (boolean). New AuditLog entity: vat_validation {customer_id, vat_id, result (valid|invalid|error), company_name, timestamp}. New document storage: exemption_certificates (customer_id → [file, upload_date]).
API
- POST /api/customers/:id/vat-id/validate { vat_id, country } → { valid, company_name, verified_date, message }
- GET /api/customers/:id/vat-id/status → { verified, date, source, expiry }
- GET /api/customers/:id/exemption-documents (list uploaded certificates)
- POST /api/customers/:id/exemption-documents/upload { file } (store certificate)
- POST /api/vat-id/bulk-validate { csv_file } → { results: [vat_id, valid, message, …] } (admin bulk import)
Every route added here must also appear in src/pages/openapi.json.ts — a test
fails the build if it does not.
Admin
Customers table gains ‘VAT ID’ column (status indicator: green checkmark for verified, red X for invalid, gray ? for unverified). Customer detail page shows VAT ID validation result, cached expiry, and exemption documents. Settings → Tax → B2B VAT: configure validation source (VIES only or include third-party), cache duration, and API credentials. Tax dashboard shows count of verified vs. unverified B2B customers.
The seam — why this is paid
Paid module owns VIES/third-party validation, customer exemption status, and certificate storage. Core owns customer record and tax calculation (calls paid module on checkout to check tax_exempt flag). Merchant owns uploading exemption documents and managing API credentials.
Paid module owns VIES API credential, VAT ID format validation per country, and tax exemption certificate storage; fiscal logic = paid (SEAM rule)
Dependencies
- Customer entity (core)
- Checkout tax calculation (core)
- Third-party integrations (VIES, Avalara, TaxJar, or country registry APIs)
- Settings (core)
Acceptance checks
Each of these must be able to fail. Before claiming this is done, break the code deliberately and watch each one go red.
- Entering a valid German VAT ID (DE123456789) and validating returns {valid: true, company_name: ’…’, verified_date: ‘2025-09-03’}
- Entering an invalid VAT ID (DE000000000) and validating returns {valid: false, message: ‘VAT ID not found in VIES’}
- Checkout to a customer with vat_id_verified=true applies 0% tax regardless of country
- Validating the same VAT ID twice within 24 hours uses cached result (no second API call)
- Admin bulk-upload CSV with 100 VAT IDs and receives results showing valid/invalid count and per-ID status
- Customer uploads an exemption certificate (PDF); it is stored and visible in customer detail page and audit log
Risks
VIES API times out or is down; validation fails and checkout stalls (need timeout + fallback: ‘assume valid, re-check later’). Cache means a deactivated VAT ID is still marked valid for 24 hours (acceptable per regulations; use cache expiry or manual invalidation). Bulk import breaks if CSV format is wrong; need format validation and error feedback. Customer disputes exemption later; need to prove we validated.
Commercial context
| Suggested price | $15-29/mo + per-validation fees (EUR 0.10-0.50/lookup) |
| Rival anchor | OO, Taxify, Exemptify (freemium, validate via VIES; $15-30/mo for real-time validation API calls) |
The anchor is what the nearest equivalent charges on Shopify or Magento today. It is context for a pricing decision, not the decision.
Generated from the commerce plan. See docs/COMMERCE-PLAN.md for the full
catalogue and ../../AI-GUIDE.md for how to work on this repository.