KVK API with PHP and Laravel: Fetch Dutch Company Data in Your Webshop or SaaS
Integrate the KVKBase API into your PHP or Laravel project. Code examples for Guzzle, WooCommerce, and Laravel — including form auto-fill and error handling.
PHP is still the backbone of the web. From WordPress plugins to Laravel SaaS platforms and WooCommerce shops, millions of developers work with PHP every day. If you have business customers who need to enter their company details, the KVKBase API is the fastest way to automate that process. In this guide we show you how to integrate the KVK API into your PHP or Laravel project.
Why PHP for KVK integrations?
PHP dominates the CMS and e-commerce landscape. More than 70% of all websites run on PHP, and a large portion of those are WooCommerce or custom Laravel applications. For B2B webshops and SaaS platforms, automatically filling in company details saves business customers a huge amount of time. With KVKBase, a single API call gives you access to company name, address, legal form, and more.
Installation
Add KVKBase to your project via Composer, or use PHP’s built-in file_get_contents function. We recommend using Guzzle for a reliable HTTP client:
composer require guzzlehttp/guzzle
Store your API key as an environment variable. In Laravel, use the .env file:
KVKBASE_API_KEY=your_...
Retrieve your API key from the KVKBase dashboard.
Basic integration with PHP (without a framework)
Below is a minimal implementation using curl for PHP projects without a framework, such as WordPress plugins:
<?php
function kvkbase_lookup_company(string $kvkNumber): ?array {
$apiKey = getenv('KVKBASE_API_KEY');
$url = "https://api.kvkbase.nl/api/v1/kvk/" . urlencode($kvkNumber);
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"X-Api-Key: {$apiKey}",
"Content-Type: application/json",
],
CURLOPT_TIMEOUT => 10,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200 || !$response) {
return null;
}
$data = json_decode($response, true);
return $data['succes'] ? $data['data'] : null;
}
Using WordPress? Add this function to functions.php and call it from a REST endpoint or AJAX handler.
Integration with Laravel (Guzzle + Service Class)
In a Laravel project, create a clean service class. This keeps your code testable and easy to mock:
<?php
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
class KvkBaseService
{
protected Client $client;
public function __construct()
{
$this->client = new Client([
'base_uri' => 'https://api.kvkbase.nl/api/v1/',
'timeout' => 10,
'headers' => [
'X-Api-Key' => config('services.kvkbase.api_key'),
'Content-Type' => 'application/json',
],
]);
}
public function lookupCompany(string $kvkNumber): ?array
{
// Cache results for 1 hour
return Cache::remember("kvk:{$kvkNumber}", 3600, function () use ($kvkNumber) {
try {
$response = $this->client->get("kvk/{$kvkNumber}");
$data = json_decode($response->getBody(), true);
return $data['succes'] ? $data['data'] : null;
} catch (RequestException $e) {
if ($e->hasResponse() && $e->getResponse()->getStatusCode() === 404) {
return null;
}
throw $e;
}
});
}
}
Register the API key in config/services.php:
'kvkbase' => [
'api_key' => env('KVKBASE_API_KEY'),
],
Laravel Controller and Route
Create a controller that uses the service:
<?php
namespace App\Http\Controllers;
use App\Services\KvkBaseService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CompanyController extends Controller
{
public function __construct(protected KvkBaseService $kvkBase) {}
public function lookup(Request $request): JsonResponse
{
$request->validate([
'kvk_number' => 'required|digits:8',
]);
$company = $this->kvkBase->lookupCompany($request->kvk_number);
if (!$company) {
return response()->json(['error' => 'Company not found'], 404);
}
return response()->json($company);
}
}
Add the route to routes/api.php:
Route::get('/company/{kvkNumber}', [CompanyController::class, 'lookup']);
Form auto-fill with Blade + Alpine.js
The most valuable use case is automatically filling in form fields as soon as a user enters their KVK number. Here’s a Blade component with Alpine.js:
<div x-data="{
kvkNumber: '',
company: null,
loading: false,
async lookup() {
if (this.kvkNumber.length !== 8) return;
this.loading = true;
const res = await fetch('/api/company/' + this.kvkNumber);
if (res.ok) this.company = await res.json();
this.loading = false;
}
}">
<input
x-model="kvkNumber"
@blur="lookup"
type="text"
name="kvk_number"
placeholder="KVK number (8 digits)"
maxlength="8"
/>
<span x-show="loading">Loading company details...</span>
<template x-if="company">
<div>
<input name="company_name" :value="company.naam" readonly />
<input name="street" :value="company.adres.straat + ' ' + company.adres.huisnummer" readonly />
<input name="postcode" :value="company.adres.postcode" readonly />
<input name="city" :value="company.adres.plaats" readonly />
</div>
</template>
</div>
This works without additional dependencies if Alpine.js is already loaded, which is the case in most modern Laravel projects that use Livewire.
WooCommerce B2B checkout
Do you have a WooCommerce shop with business customers? Add a KVK field to the checkout and automatically fill in the billing details:
<?php
// Add to functions.php of your WooCommerce theme
add_action('woocommerce_before_checkout_billing_form', function ($checkout) {
woocommerce_form_field('billing_kvk', [
'type' => 'text',
'class' => ['form-row-wide'],
'label' => 'KVK number',
'placeholder' => '12345678',
'required' => false,
], $checkout->get_value('billing_kvk'));
});
add_action('woocommerce_checkout_update_order_meta', function ($order_id) {
if (!empty($_POST['billing_kvk'])) {
update_post_meta($order_id, '_billing_kvk', sanitize_text_field($_POST['billing_kvk']));
}
});
Combine this with the JavaScript auto-fill above and your business customers only need to fill in a single field at checkout.
KVK number validation
Validate the KVK number server-side before calling the API. A valid KVK number always consists of exactly 8 digits. Read more about the validation rules in our article on KVK number validation and checksum.
function isValidKvkNumber(string $kvk): bool
{
return (bool) preg_match('/^\d{8}$/', $kvk);
}
In Laravel you can use a convenient validation rule:
$request->validate([
'kvk_number' => ['required', 'regex:/^\d{8}$/'],
]);
Caching in Laravel
KVK data rarely changes. Use Laravel’s cache to avoid unnecessary API calls:
$company = Cache::remember("kvk:{$kvkNumber}", now()->addHours(6), function () use ($kvkNumber) {
return $this->kvkBase->lookupCompany($kvkNumber);
});
For high-traffic sites, use Redis as the cache driver. This significantly speeds up your checkout and reduces your API costs.
Next steps
With this integration you have everything you need to use the KVKBase API in your PHP or Laravel project. From here you can expand with:
- CRM enrichment — automatically add company details to contacts and leads. Read more in our article on automatic CRM enrichment with company data.
- B2B onboarding — let business customers fill in only their KVK number during registration. More on this topic in our guide on B2B e-commerce business validation.
- Batch processing — enrich existing customer lists with current company data. See our guide on batch enrichment of Dutch company data in CRM.
Ready to get started? Create a free account at kvkbase.nl and you’ll have API access within a few minutes.