How to Validate VAT Numbers in Python

Validate a VAT number in Python with the Avatcado SDK. The response includes its registration status and company details when the registry provides them. This guide covers a single lookup, errors, and an async request.

Install the Python package

Use Python 3.9 or later and an Avatcado account. Single-number validation is available on Free, with 500 live validations per month. These examples were checked with Python 3.14.3 and SDK 0.6.0.

python -m venv .venv
source .venv/bin/activate
python -m pip install avatcado==0.6.0
export AVATCADO_API_KEY="avat_test_replace_with_your_key"

On Windows, activate the environment with .venv\Scripts\Activate.ps1 in PowerShell and set $env:AVATCADO_API_KEY="avat_test_replace_with_your_key". Use a test key from your dashboard. The sample number below returns a fixed test result.

Get your free API key to run this example.

Validate a VAT number

Save this as validate_vat.py and run python validate_vat.py.

import os
from avatcado import Avatcado, AvatcadoError

with Avatcado(os.environ["AVATCADO_API_KEY"], timeout=30.0) as client:
    try:
        result = client.vat.validate("DE111111111")
        print(f"Valid: {result.data.valid}")
        print(f"Number: {result.data.vat_number}")
        company = result.data.company
        print(f"Company: {company.name if company else 'Not provided'}")
        print(f"Mode: {result.meta.mode}")
    except AvatcadoError as error:
        print(f"Request failed: {error.code}: {error.message}")
        print(f"HTTP status: {error.status_code}")
        print(f"Request ID: {error.request_id}")

With a test key, DE111111111 returns Valid: True, company name Test GmbH, and Mode: test. Test calls do not query government registries or consume your monthly quota. Keep the key in the environment and out of source control.

Read the response

Python fieldValue
result.data.validRegistration status reported by the source.
result.data.vat_numberThe normalized VAT number.
result.data.companyCompany details, or None. The address may also be absent.
result.data.requested_atThe request timestamp.
result.meta.sourceThe registry or test source that supplied the result.
result.meta.cached / result.meta.staleCache and freshness information when present.

A successful request can return valid: false. Company details can be absent on a valid result. Check for None before reading the company object. Try DE222222222 with your test key to check that case.

Handle validation errors

SDK methods raise AvatcadoError subclasses for failed requests. The example prints the error code and request ID. In an application, retain those fields for troubleshooting and present the relevant error to the caller. An error leaves the registration status unresolved.

Test input or conditionResultAction
DE000000000Successful lookup with valid: false.Handle an invalid registration.
DE123invalid_vat_formatAsk for a correctly formatted number.
Missing or incorrect keyunauthorizedCheck the API-key configuration.
DE777777777rate_limit_exceededCheck the quota and any retry guidance.
DE999999999upstream_unavailableRecord the failure and try again later.

Handle unavailable registries

Live requests may use eligible cached data during an outage. Pro and Business also support national-register fallback for covered countries. Inspect the response metadata to see its source and freshness. If no eligible source can answer, the API returns a 503 error. The SDK does not retry requests automatically.

Keep the existing tax treatment and error policy in your application explicit. A failed lookup provides no new registration result. See the VIES downtime guide for the available response paths.

Use the async Python client

Use AsyncAvatcado in an asyncio application. This example awaits the single-validation endpoint. Avatcado also has separate background-validation endpoints with their own plan requirements.

import asyncio
import os
from avatcado import AsyncAvatcado, AvatcadoError

async def main():
    async with AsyncAvatcado(os.environ["AVATCADO_API_KEY"], timeout=30.0) as client:
        try:
            result = await client.vat.validate("DE111111111")
            print(result.data.valid)
        except AvatcadoError as error:
            print(f"Request failed: {error.code}: {error.message}")

asyncio.run(main())

Switch to live validation

Set AVATCADO_API_KEY to your avat_live_ key and replace the sample number with the number you need to check. Keep the country prefix. Live requests use your plan quota.

For files containing multiple numbers, follow the Python CSV guide. For a JavaScript application, see the TypeScript guide. The API integration guide covers the supported registries. The test-mode reference lists the remaining fixtures.

Sources

Related guides