KVK API met Go: Bedrijfsgegevens opvragen in Golang
Integreer de KVKBase API in je Go-project. Met codevoorbeelden voor HTTP-clients, structs, foutafhandeling en een herbruikbare client-bibliotheek — geschikt voor zowel beginners als ervaren Go-developers.
Go is een van de snelst groeiende programmeertalen voor backend-services, microservices en command-line tools. De combinatie van hoge performance, eenvoudige concurrency en een sterke standaardbibliotheek maakt Go populair bij teams die betrouwbare API-integraties willen bouwen. In deze gids laten we zien hoe je de KVKBase API integreert in je Go-project om Nederlandse bedrijfsgegevens op te vragen.
Waarom Go voor KVK-integraties?
Go heeft een uitstekende ingebouwde HTTP-client, krachtige JSON-ondersteuning en strikte typing via structs. Dat maakt het ideaal voor API-integraties waarbij je:
- Snel KVK-nummers wilt valideren bij klantregistratie
- Bedrijfsgegevens wilt ophalen voor je CRM of ERP
- Batch-verwerking wilt doen over grote lijsten van KVK-nummers
- Een microservice of interne tool bouwt die bedrijfsdata nodig heeft
De KVKBase API geeft gestructureerde JSON terug, wat naadloos aansluit op Go’s encoding/json-package en struct-definities.
Vereisten
- Go 1.21 of hoger
- Een API-key van KVKBase
- Geen externe dependencies nodig — alleen de Go standaardbibliotheek
Stap 1: Structs definiëren
Begin met het definiëren van structs die de API-response representeren. Go’s JSON-unmarshaling werkt het beste als je struct-tags toevoegt die overeenkomen met de JSON-veldnamen.
// kvkbase/types.go
package kvkbase
type Adres struct {
Straat string `json:"straat"`
Huisnummer string `json:"huisnummer"`
Postcode string `json:"postcode"`
Plaats string `json:"plaats"`
Land string `json:"land"`
}
type SbiCode struct {
Code string `json:"code"`
Omschrijving string `json:"omschrijving"`
}
type Bedrijf struct {
KvkNummer string `json:"kvkNummer"`
Naam string `json:"naam"`
Rechtsvorm string `json:"rechtsvorm"`
Actief bool `json:"actief"`
Adres Adres `json:"adres"`
SbiCodes []SbiCode `json:"sbiCodes"`
BtwNummer string `json:"btwNummer,omitempty"`
}
type APIResponse struct {
Succes bool `json:"succes"`
Data *Bedrijf `json:"data,omitempty"`
Fout string `json:"fout,omitempty"`
}
Stap 2: Een herbruikbare client bouwen
Maak een client-struct die je API-key en HTTP-client beheert. Dit is de Go-manier van werken: dependency injection in plaats van globale variabelen.
// kvkbase/client.go
package kvkbase
import (
"encoding/json"
"fmt"
"net/http"
"time"
)
const baseURL = "https://api.kvkbase.nl/api/v1"
type Client struct {
apiKey string
httpClient *http.Client
}
func NewClient(apiKey string) *Client {
return &Client{
apiKey: apiKey,
httpClient: &http.Client{
Timeout: 10 * time.Second,
},
}
}
func (c *Client) ZoekBedrijf(kvkNummer string) (*Bedrijf, error) {
url := fmt.Sprintf("%s/kvk/%s", baseURL, kvkNummer)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("aanmaken request mislukt: %w", err)
}
req.Header.Set("x-api-key", c.apiKey)
req.Header.Set("Accept", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("API-aanroep mislukt: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
return nil, fmt.Errorf("KVK-nummer %s niet gevonden", kvkNummer)
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("onverwachte statuscode: %d", resp.StatusCode)
}
var result APIResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("JSON-verwerking mislukt: %w", err)
}
if !result.Succes || result.Data == nil {
return nil, fmt.Errorf("API-fout: %s", result.Fout)
}
return result.Data, nil
}
Stap 3: Basis gebruik
// main.go
package main
import (
"fmt"
"log"
"os"
"jouwproject/kvkbase"
)
func main() {
apiKey := os.Getenv("KVKBASE_API_KEY")
if apiKey == "" {
log.Fatal("KVKBASE_API_KEY omgevingsvariabele niet ingesteld")
}
client := kvkbase.NewClient(apiKey)
bedrijf, err := client.ZoekBedrijf("12345678")
if err != nil {
log.Fatalf("Fout: %v", err)
}
fmt.Printf("Bedrijfsnaam: %s\n", bedrijf.Naam)
fmt.Printf("KVK-nummer: %s\n", bedrijf.KvkNummer)
fmt.Printf("Rechtsvorm: %s\n", bedrijf.Rechtsvorm)
fmt.Printf("Actief: %v\n", bedrijf.Actief)
fmt.Printf("Adres: %s %s, %s %s\n",
bedrijf.Adres.Straat,
bedrijf.Adres.Huisnummer,
bedrijf.Adres.Postcode,
bedrijf.Adres.Plaats,
)
}
Stap 4: Concurrency met goroutines
Een van de sterkste punten van Go is concurrency via goroutines. Dit is bijzonder handig als je een lijst van KVK-nummers wilt verwerken zonder ze één voor één sequentieel op te vragen.
// batch.go
package kvkbase
import (
"sync"
)
type BatchResultaat struct {
KvkNummer string
Bedrijf *Bedrijf
Fout error
}
func (c *Client) BulkZoek(kvkNummers []string, maxConcurrent int) []BatchResultaat {
resultaten := make([]BatchResultaat, len(kvkNummers))
sem := make(chan struct{}, maxConcurrent) // semaphore voor rate limiting
var wg sync.WaitGroup
for i, kvk := range kvkNummers {
wg.Add(1)
go func(idx int, nummer string) {
defer wg.Done()
sem <- struct{}{} // slot bezetten
defer func() { <-sem }() // slot vrijgeven
bedrijf, err := c.ZoekBedrijf(nummer)
resultaten[idx] = BatchResultaat{
KvkNummer: nummer,
Bedrijf: bedrijf,
Fout: err,
}
}(i, kvk)
}
wg.Wait()
return resultaten
}
Gebruik maxConcurrent om te voorkomen dat je de rate limits van de API overschrijdt. Een waarde van 5 tot 10 is doorgaans veilig.
nummers := []string{"12345678", "87654321", "11223344"}
resultaten := client.BulkZoek(nummers, 5)
for _, r := range resultaten {
if r.Fout != nil {
fmt.Printf("%s: FOUT - %v\n", r.KvkNummer, r.Fout)
continue
}
fmt.Printf("%s: %s (%s)\n", r.KvkNummer, r.Bedrijf.Naam, r.Bedrijf.Rechtsvorm)
}
Foutafhandeling in Go
Go’s expliciete foutafhandeling maakt de integratie robuust. De client gebruikt fmt.Errorf met %w voor fout-wrapping, zodat je upstream context behoudt:
bedrijf, err := client.ZoekBedrijf("00000000")
if err != nil {
// Specifieke fout checken
if strings.Contains(err.Error(), "niet gevonden") {
// KVK-nummer bestaat niet
fmt.Println("Onbekend KVK-nummer")
} else {
// Netwerk- of serverfout
log.Printf("API-fout: %v", err)
}
return
}
Gebruik in een HTTP-handler (Echo/Gin/chi)
Als je Go gebruikt voor een web-API, is het patroon hetzelfde. Hieronder een voorbeeld met het populaire chi-framework:
// handlers/kvk.go
package handlers
import (
"encoding/json"
"net/http"
"jouwproject/kvkbase"
"github.com/go-chi/chi/v5"
)
type KvkHandler struct {
client *kvkbase.Client
}
func NewKvkHandler(client *kvkbase.Client) *KvkHandler {
return &KvkHandler{client: client}
}
func (h *KvkHandler) GetBedrijf(w http.ResponseWriter, r *http.Request) {
kvkNummer := chi.URLParam(r, "kvkNummer")
bedrijf, err := h.client.ZoekBedrijf(kvkNummer)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(bedrijf)
}
Registreer de handler in je router:
r := chi.NewRouter()
kvkHandler := handlers.NewKvkHandler(kvkbase.NewClient(os.Getenv("KVKBASE_API_KEY")))
r.Get("/api/bedrijf/{kvkNummer}", kvkHandler.GetBedrijf)
Testing
Go’s testpakket is ingebouwd. Maak een mock HTTP-server om de client te testen zonder echte API-aanroepen:
// kvkbase/client_test.go
package kvkbase_test
import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"jouwproject/kvkbase"
)
func TestZoekBedrijf(t *testing.T) {
// Mock server opzetten
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
response := kvkbase.APIResponse{
Succes: true,
Data: &kvkbase.Bedrijf{
KvkNummer: "12345678",
Naam: "Test BV",
Rechtsvorm: "BV",
Actief: true,
},
}
json.NewEncoder(w).Encode(response)
}))
defer server.Close()
// Client aanpassen om mock te gebruiken
client := kvkbase.NewClient("test-key")
bedrijf, err := client.ZoekBedrijf("12345678")
if err != nil {
t.Fatalf("Onverwachte fout: %v", err)
}
if bedrijf.Naam != "Test BV" {
t.Errorf("Verwacht 'Test BV', kreeg '%s'", bedrijf.Naam)
}
}
Volgende stappen
Met deze basis kun je alle kanten op:
- Voeg caching toe met
sync.Mapof Redis om herhaalde lookups te vermijden - Integreer met je klant-onboarding flow om automatisch bedrijfsgegevens in te vullen (zie ook: KVK data voor klant-onboarding)
- Bouw een webhook-listener die reageert op bedrijfsstatuswijzigingen
- Combineer met bedrijfsstatus-monitoring voor proactieve alerts
Heb je vragen over de integratie of wil je je API-key aanvragen? Ga naar kvkbase.nl om aan de slag te gaan.