Part of the VAT Suite service. One request checks a VAT number: first its form (country prefix, length, structure and check digits), then its registration with the national VAT registry of the country, and returns whether the number is currently registered together with the registered name and address. All EU member states, Northern Ireland, the United Kingdom and Norway.
https://api.bav.com/validate/https://api.bav.com/validate/?api_key=YOUR_API_KEY&vat=FR64443061841application/x-www-form-urlencoded; GET takes the same parameters in the query string. Both methods return the same response. JSON request bodies are not read (result code 306).Content-Type: application/json, with non-ASCII characters escaped; the 429 and 500 cases below are the exceptions (HTML and empty bodies). There is no format parameter; one sent is ignored.active); 422 the number failed a format check, with the same body structure and result code 601–604; 400 a parameter is missing (306, 307); 403 an account problem (301–305); 429 when the rate limit is exceeded; 503 when the national registry does not answer.YOUR_API_KEY:curl "https://api.bav.com/validate/" -d api_key=YOUR_API_KEY -d vat=FR64443061841The full response to this request is in the Response section; the same request in six more languages is under Example request.
Two parameters; anything else is ignored.
| Parameter | Required | Value | Description |
|---|---|---|---|
api_key | yes | string | Your personal key, shown under API Access. Missing: HTTP 400, result code 306. Wrong or empty: HTTP 403, result code 301. |
vat | yes | string | The VAT number to check, with its country prefix (FR64443061841). Upper or lower case; spaces, full stops and hyphens are removed before the check, so BE 0567.647.463, BE0567-647-463 and fr 64 443 061 841 are read as BE0567647463 and FR64443061841. Any other character gives result code 601. Missing: HTTP 400, result code 307; empty or shorter than 4 characters: HTTP 422, result code 603. Greece is sent as EL (the ISO code GR is refused with 602), Northern Ireland as XI. |
Every example checks the same number, FR64443061841 (Google France); its response is shown in the next section. Replace YOUR_API_KEY with the key from API Access. Each sample sets a 30-second timeout, because a slow registry can take more than ten seconds to answer.
curl "https://api.bav.com/validate/" --max-time 30 \
-d api_key=YOUR_API_KEY \
-d vat=FR64443061841Five members in this order: query, valid, active, registration_data and error. The API sends the body indented with four spaces and with non-ASCII characters as \uXXXX escapes; the examples on this page are re-indented and decoded. The response to the example request:
{
"query": {
"vat": "FR64443061841",
"status": "completed",
"request_time": "2026-10-09 07:46:39"
},
"valid": true,
"active": true,
"registration_data": {
"name": "EURL GOOGLE FRANCE",
"address": "8 RUE DE LONDRES",
"city": "PARIS",
"zip": "75009",
"country_iso": "FR",
"country_name": "France"
},
"error": {}
}| Field | Type | Description |
|---|---|---|
query.vat | string | The number as it was checked: upper case, spaces, full stops and hyphens removed. Empty when an empty value was sent. |
query.status | string | completed in every recorded response. processing is defined for a national registry that does not answer (see Handling errors). |
query.request_time | string | Time the check was completed, in UTC, YYYY-MM-DD HH:MM:SS; it equals the Date header of the response, so with a slow registry it is up to 15 s after the request was sent. |
valid | boolean | true when the number passed the checks that need no registry: country prefix, length, structure and check digits. In a 200 response it is always true; a number that fails these checks is answered with HTTP 422 and false. |
active | boolean | true when the national registry lists the number as a current VAT registration. false for a well-formed number that the registry does not list as registered, and in every 422 response. |
registration_data | object | The registration as the registry delivers it, six string fields (below). An empty object {} when active is false. |
error | object | An empty object {} in a 200 response. In a 422 response, code (a number, 604) and text. See Result codes. |
| Field | Description |
|---|---|
name | Registered name of the business, in the script and case the registry uses (EURL GOOGLE FRANCE, Nokia Oyj, a Greek name in Greek letters). Non-ASCII characters are escaped as \uXXXX in the JSON text, which every JSON parser decodes. |
address | Street address. May be empty or the literal N/A when the registry has none. Some registries deliver the whole address in one field: Romania fills city and leaves address and zip empty; Northern Ireland (XI) puts the whole address in zip. Store the three fields together. |
city | City; may be empty (see above). |
zip | Postal code; may be empty, or hold the whole address (XI). |
country_iso | ISO 3166-1 alpha-2 code of the registering country: GR for a number sent with the EL prefix, GB for a number sent with XI. |
country_name | Country name in English (Czechia, United Kingdom). |
BE 0567.647.463 sent as the vat parameter: the number is checked and echoed as BE0567647463. BE0567-647-463 gives the same response; fr 64 443 061 841 is echoed as FR64443061841:
{
"query": {
"vat": "BE0567647463",
"status": "completed",
"request_time": "2026-10-09 07:46:40"
},
"valid": true,
"active": true,
"registration_data": {
"name": "BVBA Waowdeals.be",
"address": "Uitbreidingstraat 84",
"city": "Antwerpen",
"zip": "2600",
"country_iso": "BE",
"country_name": "Belgium"
},
"error": {}
}A number that passes the format and check-digit tests but is not a current VAT registration: HTTP 200, valid true, active false, registration_data empty. A company number that is not a VAT number (an Italian codice fiscale, for instance) is answered the same way:
{
"query": {
"vat": "GB999999973",
"status": "completed",
"request_time": "2026-10-09 07:59:38"
},
"valid": true,
"active": false,
"registration_data": {},
"error": {}
}Sent with the EL prefix; the name comes back in Greek letters (escaped as \uXXXX in the raw JSON) and country_iso is GR:
{
"query": {
"vat": "EL094014201",
"status": "completed",
"request_time": "2026-10-09 07:47:12"
},
"valid": true,
"active": true,
"registration_data": {
"name": "ΤΡΑΠΕΖΑ ΕΘΝΙΚΗ ΤΗΣ ΕΛΛΑΔΟΣ ΑΝΩΝΥΜΗ ΕΤΑΙΡΕΙΑ",
"address": "eolou 86",
"city": "athina",
"zip": "10559",
"country_iso": "GR",
"country_name": "Greece"
},
"error": {}
}A UK number sent with the XI prefix. The registry delivers the whole address in one field, here zip, and country_iso is GB:
{
"query": {
"vat": "XI220430231",
"status": "completed",
"request_time": "2026-10-09 07:47:15"
},
"valid": true,
"active": true,
"registration_data": {
"name": "TESCO PLC",
"address": "",
"city": "",
"zip": "CIRRUS A SHIRE PARK KESTREL WAY WELWYN GARDEN CITY AL7 1GA",
"country_iso": "GB",
"country_name": "United Kingdom"
},
"error": {}
}HTTP 422 with the full structure; here a wrong check digit (604). Note that error.code is a number and the message is in text:
{
"query": {
"vat": "FR64443061842",
"status": "completed",
"request_time": "2026-10-09 07:46:32"
},
"valid": false,
"active": false,
"registration_data": {},
"error": {
"code": 604,
"text": "Invalid VAT format, length, structure or check digit."
}
}Greece sent as GR, result code 602:
{
"query": {
"vat": "GR094014201",
"status": "completed",
"request_time": "2026-10-09 07:47:13"
},
"valid": false,
"active": false,
"registration_data": {},
"error": {
"code": 602,
"text": "Country code not supported."
}
}HTTP 400 and 403 responses carry only error, with code as a string and the message in message. A missing vat parameter:
{
"error": {
"code": "307",
"message": "Bad Request: Missing 'vat' parameter value"
}
}A wrong key (HTTP 403):
{
"error": {
"code": "301",
"message": "API Key is invalid"
}
}| Field | Type | Description |
|---|---|---|
error.code | string | The result code, as a three-digit string ("306"). |
error.message | string | The message from the code table. |
The code is in error.code. 6xx codes describe the number and come with HTTP 422, where the code is a number and the text is in error.text. 3xx codes describe the request or the account and come with HTTP 400 or 403, where the code is a string and the text is in error.message. Read the code with a parser that accepts both types.
| Code | HTTP | Text | Meaning |
|---|---|---|---|
| 601 | 422 | Invalid characters in VAT number. | After spaces, full stops and hyphens are removed, a character other than a letter or digit is left. |
| 602 | 422 | Country code not supported. | The first two characters are not a prefix the API knows: a country outside the supported list, a number sent without its prefix (64443061841), or Greece sent as GR instead of EL. |
| 603 | 422 | VAT number cannot be shorter than 4 characters. | The value is empty or shorter than four characters. |
| 604 | 422 | Invalid VAT format, length, structure or check digit. | The prefix is known but the rest does not fit that country’s format, or its check digits are wrong. The registry is not consulted. |
No lookup is performed and no query is used. 301, 306 and 307 were recorded; 302 to 305 follow the same path with their own message.
| Code | HTTP | Message | What to do |
|---|---|---|---|
| 301 | 403 | API Key is invalid | Copy the key exactly as shown under API Access; an empty key gives the same answer. |
| 302 | 403 | Subscription expired | Renew the VAT Suite service under My Services. |
| 303 | 403 | No queries available | Your query balance is used up; top up under Pricing. |
| 304 | 403 | You have no access to this API | The VAT Suite service is not active on this account. |
| 305 | 403 | IP Address not allowed | The key is restricted to certain IP addresses; add the calling server’s address under Settings. |
| 306 | 400 | Bad Request: Missing 'api_key' parameter value | Send api_key. Also the answer to a JSON request body, which is not read: send a form body. |
| 307 | 400 | Bad Request: Missing 'vat' parameter value | Send vat. |
| HTTP | Body | Meaning |
|---|---|---|
| 429 | HTML page | More than 20 requests per second; see Rate limits. |
| 500 | empty, text/html | A parameter was sent in a form the API cannot read, such as vat[]. Send plain string parameters. |
| 503 | JSON, result code 503, National registry not responding. Try again later. | The registry of the country did not answer; the query is not charged. Retry later. Not observed in the recorded calls. |
What each outcome means for your code. The format checks are deterministic; the registration status is not, so do not cache active for long — a registration can be cancelled at any time, and tax authorities expect a check at the time of each supply.
| Situation | Meaning | What to do |
|---|---|---|
| HTTP 200 | The number is well-formed and the registry answered. The outcome is active. | Do not retry. Store the result with request_time. |
| HTTP 422, result code 601–604 | The number failed a check that needs no registry: characters, prefix, length, structure or check digits. The query is charged. | Do not retry: the same input gives the same result. Show the user the text, log the code. |
| HTTP 400, result code 306 or 307 | A required parameter is missing. Only error is in the body. | Fix the request. Do not retry it unchanged. |
| HTTP 403, result code 301 or 304 | The key is wrong, or the VAT Suite service is not on the account. | Stop sending; every request will fail the same way. Check the key under API Access, or contact support for 304. |
| HTTP 403, result code 302 or 303 | The service has expired, or the query balance is used up. | Stop sending and alert whoever handles the subscription. Poll the services endpoint to catch this before it happens. |
| HTTP 403, result code 305 | The calling address is not on the key’s IP allow-list. | Add the address under Settings, then resend. |
| HTTP 429, HTML body | More than 20 requests per second. The request was rejected by the web server before reaching the API: not processed, not charged. | Wait a moment and resend; lower the sending rate. Safe to retry. There is no Retry-After header. |
HTTP 503, or query.status processing | The national registry did not answer in time. Not charged. | Retry the same number later, with increasing delays (30 s, 2 min, 10 min); national registries have maintenance windows. |
| HTTP 5xx (other), timeout, connection error | Temporary problem on the way to the API or on the API itself. | Retry with increasing delays (1 s, 2 s, 4 s, then give up and queue). A request that got no response may still have been processed and charged. |
active. valid true only says the number is well-formed; a number that is not registered can be well-formed too (HTTP 200, active false).query.vat), request_time, active and the registered name and address with the transaction.EURL GOOGLE FRANCE, Telefonica sa).EL for Greece, XI for Northern Ireland, GB for the rest of the United Kingdom. Spaces, full stops, hyphens and lower case are fine; any other character gives 601.The 27 EU member states, Northern Ireland, the United Kingdom and Norway. 29 of the 30 prefixes were looked up successfully during recording (marked); the format column is the one published by the national registries. A prefix outside this list is refused with result code 602 (recorded for AU, US and XX); Switzerland is the exception, see below.
| Prefix | Country | Format after the prefix | Lookup |
|---|---|---|---|
AT | Austria | U + 8 digits (ATU99999999) | recorded |
BE | Belgium | 10 digits, first digit 0 or 1 | recorded, up to 4.0 s |
BG | Bulgaria | 9 or 10 digits | recorded |
CY | Cyprus | 8 digits + 1 letter | recorded |
CZ | Czechia | 8, 9 or 10 digits | recorded, up to 9.4 s |
DE | Germany | 9 digits | recorded, up to 1.4 s |
DK | Denmark | 8 digits | recorded, up to 15.2 s |
EE | Estonia | 9 digits | recorded |
EL | Greece | 9 digits (prefix EL, not GR) | recorded |
ES | Spain | 9 characters; the first, the last or both are letters | recorded |
FI | Finland | 8 digits | recorded |
FR | France | 2 characters + 9 digits (SIREN) | recorded, up to 5.0 s |
HR | Croatia | 11 digits (OIB) | recorded |
HU | Hungary | 8 digits | recorded |
IE | Ireland | 8 or 9 characters with one or two letters: the last, the second and the last, or the last two | recorded |
IT | Italy | 11 digits | recorded, up to 3.0 s |
LT | Lithuania | 9 or 12 digits | recorded |
LU | Luxembourg | 8 digits | recorded |
LV | Latvia | 11 digits | recorded, up to 8.7 s |
MT | Malta | 8 digits | not recorded |
NL | Netherlands | 9 digits + B + 2 digits | recorded, up to 1.6 s |
PL | Poland | 10 digits (NIP) | recorded |
PT | Portugal | 9 digits (NIF) | recorded |
RO | Romania | 2 to 10 digits | recorded |
SE | Sweden | 12 digits, ending in 01 | recorded |
SI | Slovenia | 8 digits | recorded |
SK | Slovakia | 10 digits | recorded |
XI | Northern Ireland | 9 or 12 digits (a UK number with the XI prefix) | recorded |
GB | United Kingdom | 9 or 12 digits, or GD / HA + 3 digits | recorded |
NO | Norway | 9 digits (organisation number) | recorded |
Switzerland is not available: the prefix is recognised, but a Swiss number in any spelling (CHE-116.281.710, with or without MWST, CH116281710) is refused with 604.
The services endpoint returns every service on your account with its remaining queries and expiry date, the same information as My Services. Poll it from your monitoring to catch a low balance before the API starts answering 303. It takes your api_key and a format (json or xml) and does not use a query.
https://api.iban.com/clients/api/v4/services/?api_key=YOUR_API_KEY&format=jsonhttps://api.iban.com/clients/api/v4/services/?api_key=YOUR_API_KEY&format=xmlThe response, shortened to the entry of this service (the endpoint lists every service on your account, one object each):
{
"services": [
{
"service_name": "VAT Suite (2,000)",
"credits": 1968,
"expiry_date": "2027-10-09",
"service_expired": 0
}
],
"errors": []
}The HTTP status is 200 in every case. With a wrong key, services is empty and errors carries code 301 ({"services":[],"errors":[{"code":"301","message":"API Key is invalid"}]}); without format the body is empty.
| Field | Type | Description |
|---|---|---|
service_name | string | Name of the service as shown under My Services. The VAT Suite entry carries the plan size in brackets: VAT Suite (2,000). Match on the prefix VAT Suite. |
credits | number or string | Remaining queries. Services without a quota return the string Unlimited instead of a number, so test the type before comparing. |
expiry_date | string | Expiry date of the service, YYYY-MM-DD. Requests after this date are refused as expired. |
service_expired | 0 or 1 | 1 when the service has expired. |
| Term | Meaning |
|---|---|
| VAT number | The identifier a business is registered under for value-added tax, also called VAT ID or VAT registration number: a two-letter country prefix followed by the national number. The national part is often the company number (SIREN in France, CVR in Denmark, organisation number in Sweden and Norway) or a tax number (NIP, NIF). |
| Prefix | The first two characters. They follow ISO 3166-1 with two exceptions: Greece uses EL, and Northern Ireland uses XI since 2021 for goods traded under the Northern Ireland Protocol. |
| Check digit | One or more digits computed from the rest of the number by the issuing country’s algorithm (modulus 97 in Belgium and France, ISO 7064 MOD 11,10 in Germany, modulus 11 in the Netherlands, Luhn in Italy and Sweden). A wrong check digit gives result code 604 without a registry lookup. |
| Valid / active | valid means well-formed; active means currently registered. A number can be well-formed and not registered, so use active for decisions. |
| Registration data | The name and address under which the number is registered, as delivered by the national registry. Format, case and script are the registry’s. |
| VIES | VAT Information Exchange System, the European Commission’s system through which the EU member states and Northern Ireland publish the registration status of their VAT numbers. |
| Reverse charge | In business-to-business supplies across EU borders the customer, not the supplier, accounts for the VAT; the supplier must hold a valid VAT number of the customer at the time of the supply, which is the usual reason to call this API and to keep the result with its request_time. |