KVK API with Node.js and TypeScript: The Complete Developer Guide
KVKBase Team

KVK API with Node.js and TypeScript: The Complete Developer Guide

Integrate the KVKBase API into your Node.js or TypeScript project. Code examples for Express, Next.js, and NestJS — including type definitions and error handling.

kvkapinodejstypescriptjavascriptdevelopers

Node.js and TypeScript are the most widely used technologies for modern web applications and SaaS products. If you want to look up company information, validate KVK numbers, or onboard B2B customers, the KVK API by KVKBase is the fastest way to do it. In this guide, we walk you through integrating the API into your Node.js or TypeScript project step by step.

Why Node.js and TypeScript for KVK integrations?

JavaScript and TypeScript dominate the web ecosystem. Whether you’re building an API with Express or Fastify, a full-stack app with Next.js, or an enterprise application with NestJS — at some point you’ll need to fetch Dutch company data. And it’s much nicer to work in a type-safe way with API responses.

The KVKBase API returns structured JSON, which is perfect for TypeScript projects. Define the types once, and the rest of your codebase automatically benefits from autocomplete and compile-time checks.

Installation and setup

No external SDK needed. The KVKBase API works with plain HTTP requests. In this guide we use fetch (available in Node.js 18+) for the simplest approach.

First, create a .env file with your API key:

KVKBASE_API_KEY=your_api_key_here

You can get your API key from the KVKBase dashboard.

Defining TypeScript types

Start by defining types for the API response. This gives you full autocomplete in your editor and prevents runtime errors:

// types/kvkbase.ts

export interface KvkCompany {
  kvkNummer: string;
  naam: string;
  rechtsvorm: string;
  actief: boolean;
  adres: {
    straat: string;
    huisnummer: string;
    postcode: string;
    plaats: string;
    land: string;
  };
  sbiCodes: SbiCode[];
  btwNummer?: string;
}

export interface SbiCode {
  code: string;
  omschrijving: string;
}

export interface KvkBaseResponse {
  succes: boolean;
  data?: KvkCompany;
  fout?: string;
}

Making the KVK API call

Here is a reusable function to fetch company data:

// lib/kvkbase.ts

import type { KvkBaseResponse, KvkCompany } from '../types/kvkbase';

const API_URL = 'https://api.kvkbase.nl/api/v1';
const API_KEY = process.env.KVKBASE_API_KEY!;

export async function lookupCompany(kvkNumber: string): Promise<KvkCompany | null> {
  const response = await fetch(`${API_URL}/kvk/${kvkNumber}`, {
    headers: {
      'X-Api-Key': API_KEY,
      'Content-Type': 'application/json',
    },
  });

  if (!response.ok) {
    if (response.status === 404) return null;
    throw new Error(`KVKBase API error: ${response.status}`);
  }

  const data: KvkBaseResponse = await response.json();
  return data.succes ? (data.data ?? null) : null;
}

Integration with Express

Here is how to add a KVK lookup endpoint to your Express application:

// routes/company.ts

import express from 'express';
import { lookupCompany } from '../lib/kvkbase';

const router = express.Router();

router.get('/company/:kvkNumber', async (req, res) => {
  const { kvkNumber } = req.params;

  if (!/^\d{8}$/.test(kvkNumber)) {
    return res.status(400).json({ error: 'Invalid KVK number (8 digits expected)' });
  }

  const company = await lookupCompany(kvkNumber);

  if (!company) {
    return res.status(404).json({ error: 'Company not found' });
  }

  res.json(company);
});

export default router;

Integration with Next.js App Router

With Next.js 13+, use Route Handlers for server-side API calls:

// app/api/company/[kvkNumber]/route.ts

import { NextRequest, NextResponse } from 'next/server';
import { lookupCompany } from '@/lib/kvkbase';

export async function GET(
  request: NextRequest,
  { params }: { params: { kvkNumber: string } }
) {
  const { kvkNumber } = params;

  if (!/^\d{8}$/.test(kvkNumber)) {
    return NextResponse.json(
      { error: 'Invalid KVK number' },
      { status: 400 }
    );
  }

  const company = await lookupCompany(kvkNumber);

  if (!company) {
    return NextResponse.json({ error: 'Not found' }, { status: 404 });
  }

  return NextResponse.json(company);
}

You can then use this in a client component with SWR or React Query for real-time lookup as the user types.

Form auto-fill in Next.js

One of the most valuable use cases is automatically filling in form fields based on the KVK number. Here is a React component:

// components/CompanyDetailsForm.tsx

'use client';

import { useState } from 'react';
import type { KvkCompany } from '@/types/kvkbase';

export function CompanyDetailsForm() {
  const [kvkNumber, setKvkNumber] = useState('');
  const [company, setCompany] = useState<KvkCompany | null>(null);
  const [loading, setLoading] = useState(false);

  async function lookup() {
    if (kvkNumber.length !== 8) return;
    setLoading(true);
    const res = await fetch(`/api/company/${kvkNumber}`);
    if (res.ok) setCompany(await res.json());
    setLoading(false);
  }

  return (
    <form>
      <input
        type="text"
        value={kvkNumber}
        onChange={(e) => setKvkNumber(e.target.value)}
        onBlur={lookup}
        placeholder="KVK number (8 digits)"
        maxLength={8}
      />
      {loading && <span>Fetching company data...</span>}
      {company && (
        <>
          <input name="companyName" value={company.naam} readOnly />
          <input name="street" value={company.adres.straat} readOnly />
          <input name="postalCode" value={company.adres.postcode} readOnly />
          <input name="city" value={company.adres.plaats} readOnly />
        </>
      )}
    </form>
  );
}

Caching for better performance

KVK data rarely changes. Cache your responses to avoid unnecessary API calls and improve speed:

// lib/kvkbase.ts — with in-memory cache

const cache = new Map<string, { data: KvkCompany; timestamp: number }>();
const CACHE_TTL = 3600 * 1000; // 1 hour

export async function lookupCompany(kvkNumber: string): Promise<KvkCompany | null> {
  const cached = cache.get(kvkNumber);
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
    return cached.data;
  }

  const company = await fetchCompanyFromApi(kvkNumber);
  if (company) {
    cache.set(kvkNumber, { data: company, timestamp: Date.now() });
  }
  return company;
}

For production environments, use Redis or a similar in-memory store. With Next.js, you can also use the built-in fetch cache with { next: { revalidate: 3600 } }.

Error handling and retry logic

Robust applications need solid error handling. Here is a pattern with exponential backoff:

async function fetchWithRetry<T>(
  url: string,
  options: RequestInit,
  maxAttempts = 3
): Promise<T> {
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const response = await fetch(url, options);

    if (response.ok) return response.json() as Promise<T>;
    if (response.status === 404) throw new Error('Not found');
    if (response.status === 429) {
      // Rate limit: wait before next attempt
      await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, attempt)));
      continue;
    }

    throw new Error(`API error: ${response.status}`);
  }
  throw new Error('Max attempts reached');
}

Client-side KVK number validation

Validate the KVK number on the client side before making an API call. A valid KVK number always has 8 digits and follows checksum rules. More details about the validation rules are in our article on KVK number validation and checksum.

export function isValidKvkNumber(kvk: string): boolean {
  if (!/^\d{8}$/.test(kvk)) return false;
  // Basic format check; for full checksum validation: see KVKBase docs
  return true;
}

Next steps

With this integration you have a solid foundation for fetching Dutch company data in your Node.js or TypeScript project. From here you can:

  • Automate B2B onboarding — let customers fill in only their KVK number
  • Enrich your CRM — automatically add company data to leads
  • Optimize checkout — faster checkout for business customers

Also check out our Python guide for the KVK API if you have a Python backend, or read more about looking up KVK numbers for a broader introduction.

Ready to get started? Create a free account at kvkbase.nl and you’ll have API access within minutes.