Documentation
Base URL: https://api.klik-shop.nl. All responses are JSON. Authenticate with the X-API-Key header. No key yet? Get one for free.
Quick start
# Single number
curl https://api.klik-shop.nl/v1/vat/NL004495445B01 \
-H "X-API-Key: btw_your_key"
# Batch (max 50)
curl -X POST https://api.klik-shop.nl/v1/vat/batch \
-H "X-API-Key: btw_your_key" -H "Content-Type: application/json" \
-d '{"vat_numbers": ["NL004495445B01", "BE0403170701", "DE811191002"]}'
# VAT rates and IBAN (no key needed)
curl https://api.klik-shop.nl/v1/rates/NL
curl https://api.klik-shop.nl/v1/iban/NL91ABNA0417164300const res = await fetch("https://api.klik-shop.nl/v1/vat/" + encodeURIComponent(vatNumber), {
headers: { "X-API-Key": process.env.BTW_API_KEY }
});
const data = await res.json();
if (res.ok) {
console.log(data.valid ? "Valid" : "Invalid", data.name);
} else if (res.status === 503) {
// VIES outage: do not treat as invalid, retry later
console.warn(data.error.advice);
} else {
console.error(data.error.code, data.error.message);
}<?php
$ch = curl_init("https://api.klik-shop.nl/v1/vat/" . rawurlencode($vatNumber));
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["X-API-Key: " . getenv("BTW_API_KEY")],
CURLOPT_TIMEOUT => 15,
]);
$data = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status === 200) {
echo $data["valid"] ? "Valid: " . $data["name"] : "Invalid";
} elseif ($status === 503) {
// VIES outage: accept provisionally and re-check later
error_log($data["error"]["advice"]);
}
Endpoints
| Endpoint | Key | What |
|---|---|---|
GET /v1/vat/{vat_number} | yes (1 check) | Checks one number, e.g. NL004495445B01. Spaces, dots and dashes are allowed. GR becomes EL; XI = Northern Ireland. |
POST /v1/vat/batch | yes (1 per number) | Body {"vat_numbers": [...]}, max 50. You get ok plus the result or an error per number. charged = checks deducted. |
GET /v1/rates, GET /v1/rates/{country} | no | VAT rates (standard, reduced, super-reduced, parking) for the 27 EU countries, with source and date. |
GET /v1/iban/{iban} | no | Length and mod-97 checksum validation. No bank lookup. |
GET /v1/status | no | VIES availability per member state (cached 5 min). |
GET /v1/account | yes (free) | Usage this month, free checks left and credit. |
Response fields
valid | true/false according to VIES |
name, address | As registered, or null if the member state doesn't share them |
source | vies (live), cache (< 24 h old) or cache_stale (VIES outage, last known result up to 7 days, with a warning) |
checked_at, cache_age_seconds | Time of the underlying VIES check |
Errors
Errors always look like {"error": {"code", "message", ...}}.
| HTTP | code | Meaning |
|---|---|---|
| 400 | invalid_format | Number doesn't match the country format (not charged) |
| 401 | missing_api_key, invalid_api_key | Header missing or key unknown |
| 402 | quota_exceeded | Free checks and credit used up. Buy credit |
| 429 | rate_limited | More than 60 requests per minute per key (see Retry-After) |
| 503 | service_unavailable | VIES or the member state's tax authority is unreachable. Not charged. See advice below. |
{
"error": {
"code": "service_unavailable",
"message": "VIES or the national VAT database of DE is temporarily unavailable (MS_UNAVAILABLE).",
"advice": "This does NOT mean the number is invalid. Retry after about 60 seconds. ...",
"vies_error": "MS_UNAVAILABLE",
"retry_after_seconds": 60
}
}
Advice on 503: do not treat the number as invalid. Retry after about 60 seconds (
Retry-After header). In a checkout, accept the order provisionally and re-check later. Use GET /v1/status to see which member state is down.Limits and usage
- 5 free checks per calendar month (UTC) per key, then your prepaid credit is used.
- Max 60 requests per minute per key. A batch call counts as one request.
- Response headers:
X-Quota-RemainingandX-RateLimit-Remaining. - Max 3 new keys per network per day.
Sources
VAT numbers: VIES, European Commission. Rates: Taxes in Europe Database (TEDB), snapshot of 1 November 2026. Always verify rates for tax filings with the national tax authority.