Error Codes

All API errors follow a consistent format. The HTTP status code indicates the category of error, and the response body contains a machine-readable error code and a human-readable message.

Error response format

Every error response has this structure:

json
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Company not found for KVK number 99999999"
  }
}

Error code reference

All possible error codes, their HTTP status, and common causes:

NOT_FOUND 404

No company found for the given identifier.

Common cause: The KVK number, VAT number, or search query returned no results. Verify the number is correct and that the company is registered.
INVALID_KVK_NUMBER 400

The provided KVK number is not valid.

Common cause: KVK numbers must be exactly 8 digits. Check for extra spaces, dashes, or letters in the input.
INVALID_VAT_NUMBER 400

The provided VAT number format is not recognized.

Common cause: Dutch VAT numbers follow the format NL + 9 digits + B + 2 digits (e.g. NL123456789B01). EU VAT numbers must start with a valid country code.
INVALID_REQUEST 400

The request is missing required parameters or has invalid values.

Common cause: Check required fields: search needs a q parameter with at least 2 characters, batch needs an array of KVK numbers, etc.
UNAUTHORIZED 401

Missing or invalid API key.

Common cause: Ensure you are sending a valid key via the Authorization header (Bearer token) or apikey query parameter. Keys start with kvk_live_ or kvk_test_.
RATE_LIMIT_EXCEEDED 429

Too many requests in the current time window.

Common cause: You have exceeded the per-minute rate limit for your plan. Check the Retry-After header and wait before retrying. Consider upgrading for higher limits.
QUOTA_EXCEEDED 429

Monthly token allowance exhausted.

Common cause: You have used all tokens for this billing cycle. Upgrade your plan or wait until the next month. Check X-Tokens-Remaining header to monitor usage.
UPSTREAM_ERROR 502

An upstream service is temporarily unavailable.

Common cause: The KVK API or VIES service is not responding. This is usually temporary. Retry after a short delay. Check /v1/health for service status.
INTERNAL_ERROR 500

An unexpected server error occurred.

Common cause: This should not happen in normal operation. If it persists, contact support with the request ID from the response headers.

Handling errors

We recommend checking the HTTP status code first, then parsing the error body for the specific error code:

javascript
const res = await fetch("https://api.kvkbase.nl/v1/lookup/12345678", {
  headers: { Authorization: "Bearer YOUR_API_KEY" },
});

if (!res.ok) {
  const { error } = await res.json();

  switch (error.code) {
    case "NOT_FOUND":
      console.log("Company not found");
      break;
    case "RATE_LIMIT_EXCEEDED":
      const retryAfter = res.headers.get("Retry-After");
      console.log(`Rate limited. Retry after ${retryAfter}s`);
      break;
    case "QUOTA_EXCEEDED":
      console.log("Monthly token quota reached");
      break;
    case "UNAUTHORIZED":
      console.log("Invalid API key");
      break;
    default:
      console.error("API error:", error.message);
  }
}

Rate limit headers

Every API response includes headers with rate limit and token usage information. Use these to monitor your usage and avoid hitting limits.

Header Description Example
X-RateLimit-Limit Maximum requests per minute for your plan 60
X-RateLimit-Remaining Requests remaining in the current window 58
X-RateLimit-Reset Unix timestamp when the rate limit window resets 1710676800
X-Tokens-Remaining Tokens remaining for the current billing cycle 847
Retry-After Seconds to wait before retrying (only on 429 responses) 12

Retry strategy

For production applications, we recommend implementing exponential backoff:

javascript
async function kvkLookup(kvkNumber, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const res = await fetch(
      `https://api.kvkbase.nl/v1/lookup/${kvkNumber}`,
      { headers: { Authorization: "Bearer YOUR_API_KEY" } }
    );

    if (res.ok) return res.json();

    if (res.status === 429) {
      const wait = parseInt(res.headers.get("Retry-After") || "5");
      await new Promise(r => setTimeout(r, wait * 1000));
      continue;
    }

    if (res.status === 502) {
      // Upstream error -- wait and retry
      await new Promise(r => setTimeout(r, (attempt + 1) * 2000));
      continue;
    }

    // Non-retryable error
    const { error } = await res.json();
    throw new Error(error.message);
  }
  throw new Error("Max retries exceeded");
}