API Reference

Base URL https://api.kvkbase.nl/v1

Authentication

All endpoints (except /v1/health) require an API key. Two methods are supported:

Query Parameter

?apikey=YOUR_API_KEY

Get your API key from the Dashboard. Keys are scoped to your account tier and rate limits.

GET /v1/lookup/{kvkNumber}

Company Lookup

Look up detailed company information by KVK number. Returns company name, address, legal form, activities, and VIES-validated VAT number in a single call. The vat object carries a status of validated, stale, malformed or unvalidated, so a VIES outage never reaches you as a false negative. See the Error Codes page for what each one means.

Parameters

kvkNumber required
string
8-digit KVK number (path parameter)
vat
boolean
Set to true to fetch the KVK Basisprofiel: VAT number (validated through VIES), employee counts, statutory name, formal registration date and the official SBI descriptions. Costs 12 tokens instead of 2. The VAT number is derived from the RSIN, so it is only returned for legal persons such as a BV or NV; a sole trader or partnership has no RSIN in the register and gets vat: null. The other fields are returned for every legal form.

Request

curl -X GET "https://api.kvkbase.nl/v1/lookup/12345678" \
  -H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch(
  "https://api.kvkbase.nl/v1/lookup/12345678",
  {
    headers: {
      Authorization: "Bearer YOUR_API_KEY",
    },
  }
);
const company = await response.json();
console.log(company.name); // "Acme B.V."
import requests

response = requests.get(
    "https://api.kvkbase.nl/v1/lookup/12345678",
    headers={"Authorization": "Bearer YOUR_API_KEY"}
)
company = response.json()
print(company["name"])  # "Acme B.V."
$ch = curl_init("https://api.kvkbase.nl/v1/lookup/12345678");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_KEY"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = json_decode(curl_exec($ch));
echo $response->name; // "Acme B.V."
req, _ := http.NewRequest("GET",
    "https://api.kvkbase.nl/v1/lookup/12345678", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")

resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()

var company map[string]interface{}
json.NewDecoder(resp.Body).Decode(&company)
fmt.Println(company["name"]) // "Acme B.V."
require "net/http"
require "json"

uri = URI("https://api.kvkbase.nl/v1/lookup/12345678")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http|
  http.request(req)
}
company = JSON.parse(res.body)
puts company["name"] # "Acme B.V."

Response

{
  "kvkNumber": "12345678",
  "name": "Acme B.V.",
  "tradingNames": ["Acme", "Acme Trading"],
  "legalForm": "BV",
  "address": {
    "street": "Herengracht",
    "houseNumber": "100",
    "postalCode": "1015 AA",
    "city": "Amsterdam",
    "country": "NL"
  },
  "isActive": true,
  "registrationDate": "2020-01-15",
  "activities": [
    { "sbiCode": "6201", "description": "Ontwikkelen en uitgeven van software", "isMain": true }
  ],
  "vat": {
    "number": "NL123456789B01",
    "valid": true,
    "status": "validated",
    "validatedAt": "2026-03-15T12:00:00Z",
    "checksumValid": true
  },
  "source": {
    "kvk": "opendata+zoeken",
    "vies": "validated",
    "cachedAt": "2026-03-15T12:00:00Z"
  }
}
GET /v1/validate/vat/{vatNumber}

VAT Validation

Validate a Dutch or EU VAT number against the VIES system. Returns validation status and registered company details. When a member state service is down, status tells you whether you are looking at a live verdict (validated), a dated one we obtained earlier (stale, with ageSeconds), or a number the Dutch checksum rejects outright (malformed). A 502 UPSTREAM_ERROR is reserved for when we have none of those. checksumValid is the Dutch elfproef: it means well formed, never valid.

Parameters

vatNumber required
string
VAT number, e.g. NL123456789B01 (path parameter)

Request

curl -X GET "https://api.kvkbase.nl/v1/validate/vat/NL123456789B01" \
  -H "Authorization: Bearer YOUR_API_KEY"
const response = await fetch(
  "https://api.kvkbase.nl/v1/validate/vat/NL123456789B01",
  { headers: { Authorization: "Bearer YOUR_API_KEY" } }
);
const { valid, name } = await response.json();
response = requests.get(
    "https://api.kvkbase.nl/v1/validate/vat/NL123456789B01",
    headers={"Authorization": "Bearer YOUR_API_KEY"}
)
result = response.json()
print(f"Valid: {result['valid']}")
$ch = curl_init(
    "https://api.kvkbase.nl/v1/validate/vat/NL123456789B01"
);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer YOUR_API_KEY"
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$result = json_decode(curl_exec($ch));
req, _ := http.NewRequest("GET",
    "https://api.kvkbase.nl/v1/validate/vat/NL123456789B01", nil)
req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
resp, _ := http.DefaultClient.Do(req)
uri = URI("https://api.kvkbase.nl/v1/validate/vat/NL123456789B01")
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"

Response

{
  "vatNumber": "NL123456789B01",
  "valid": true,
  "name": "Acme B.V.",
  "address": "Herengracht 100, 1015 AA Amsterdam",
  "validatedAt": "2026-03-15T12:00:00Z",
  "status": "validated",
  "checksumValid": true
}
GET /v1/health

Health Check

Check API and upstream service status. No authentication required.

Request

curl https://api.kvkbase.nl/v1/health
const response = await fetch("https://api.kvkbase.nl/v1/health");
const health = await response.json();
console.log(health.status); // "ok"
response = requests.get("https://api.kvkbase.nl/v1/health")
print(response.json()["status"])  # "ok"
$health = json_decode(
    file_get_contents("https://api.kvkbase.nl/v1/health")
);
resp, _ := http.Get("https://api.kvkbase.nl/v1/health")
res = Net::HTTP.get(URI("https://api.kvkbase.nl/v1/health"))

Response

{
  "status": "ok",
  "services": {
    "kvk": "up",
    "vies": "up"
  },
  "timestamp": "2026-03-15T12:00:00Z"
}

Errors

All errors return a consistent JSON format:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "No company found with KVK number 99999999"
  }
}

See the Error Codes page for a complete reference with HTTP status codes.

Rate Limits

Rate limits are applied per API key based on your plan tier:

Tier
Rate Limit
Headers
free
10 req/min
X-RateLimit-Limit, X-RateLimit-Remaining
starter
60 req/min
X-RateLimit-Limit, X-RateLimit-Remaining
pro
300 req/min
X-RateLimit-Limit, X-RateLimit-Remaining
business
1,000 req/min
X-RateLimit-Limit, X-RateLimit-Remaining

Token Costs

Call
Cost
Notes
Basic lookup
1 token
Name, address, status
Enriched lookup
2 tokens
Trade names, address, legal form, SBI codes and branches (?enrich=true)
Enriched via KVK Basisprofiel
12 tokens
Adds employee counts, statutory name, registration date and official SBI descriptions, plus the VAT number for legal persons (?enrich=true&vat=true)
Search
1 token
Per search request
Branches
5 tokens
All branches for a company
Verify
Free
Existence and active status

When rate limited, the API returns 429 Too Many Requests with a Retry-After header.