Denne guide viser dig, hvordan du integrerer DataCVR API i din applikation trin for trin. Uanset om du bygger en webapplikation, et CRM-system, eller automatiserer din faktureringsproces, finder du her komplette kodeeksempler i JavaScript, Python, PHP og C# — klar til at kopiere og tilpasse.
Forudsætninger
Før du starter, skal du have følgende på plads:
- Gratis konto: Opret en konto på datacvrapi.dk (tager under 1 minut)
- API-nøgle: Find din API-nøgle i dit dashboard under "API-nøgle"
- HTTP-klient: Dit foretrukne programmeringssprog med en HTTP-klient (fetch, requests, cURL, HttpClient)
Den gratis plan giver 10 opslag per dag — nok til at udvikle og teste din integration. Se den fulde API-dokumentation for alle tilgængelige endpoints.
JavaScript / Node.js integration
JavaScript er det mest populære sprog til API-integrationer. Her er en komplet implementering med fejlhåndtering:
Simpelt opslag med fetch
// cvr-client.js — Simpelt CVR-opslag
async function hentVirksomhed(cvrNummer) {
const API_KEY = process.env.DATACVR_API_KEY;
const BASE_URL = 'https://datacvrapi.dk/api/v2';
const response = await fetch(
`${BASE_URL}/dk/company/${cvrNummer}`,
{
headers: {
'Authorization': `Bearer ${API_KEY}`
}
}
);
if (!response.ok) {
const error = await response.json().catch(() => ({}));
throw new Error(
`CVR opslag fejlede: ${response.status} — ${error.message || 'Ukendt fejl'}`
);
}
return response.json();
}
// Brug
const virksomhed = await hentVirksomhed('44474117');
console.log(virksomhed.name); // "Branthiq ApS"
console.log(virksomhed.address); // { street: "Ryesgade 3A", ... }
console.log(virksomhed.protected); // true (reklamebeskyttet)
console.log(virksomhed.owners); // [{ name: "Benjamin Falkentoft", role: "ADM. DIR.", ... }]
Komplet klient med retry og caching
// datacvr-client.js — Komplet klient
class DataCvrClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://datacvrapi.dk/api/v2';
this.cache = new Map();
this.cacheTtl = 3600000; // 1 time i millisekunder
}
async request(endpoint, options = {}) {
// Tjek cache
const cacheKey = endpoint;
const cached = this.cache.get(cacheKey);
if (cached && Date.now() - cached.timestamp < this.cacheTtl) {
return cached.data;
}
// Lav request med retry
let lastError;
for (let attempt = 0; attempt < 3; attempt++) {
try {
const response = await fetch(
`${this.baseUrl}${endpoint}`,
{
...options,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json',
...options.headers
}
}
);
if (response.status === 429) {
// Rate limited — vent og prøv igen
const ventetid = Math.pow(2, attempt) * 1000;
await new Promise(r => setTimeout(r, ventetid));
continue;
}
if (!response.ok) {
throw new Error(`API fejl: ${response.status}`);
}
const data = await response.json();
// Gem i cache
this.cache.set(cacheKey, {
data,
timestamp: Date.now()
});
return data;
} catch (error) {
lastError = error;
}
}
throw lastError;
}
// Hent virksomhedsdata
async hentVirksomhed(cvr) {
return this.request(`/dk/company/${cvr}`);
}
// Hent regnskabsdata (Business+)
async hentRegnskab(cvr) {
return this.request(`/dk/company/${cvr}/accounts`);
}
// Hent cached kontakter (Business+)
async hentKontakter(cvr) {
return this.request(`/contacts/${cvr}`);
}
}
// Brug
const client = new DataCvrClient('DIN_API_NØGLE');
const data = await client.hentVirksomhed('44474117');
console.log(data.name); // "Branthiq ApS"
Python integration
Python er ideelt til datanalyse, scripting og backend-systemer. Her er en komplet integration med requests-biblioteket:
# datacvr_client.py — Python CVR-klient
import requests
import time
import os
from functools import lru_cache
class DataCvrClient:
def __init__(self, api_key=None):
self.api_key = api_key or os.environ.get("DATACVR_API_KEY")
self.base_url = "https://datacvrapi.dk/api/v2"
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Bearer {self.api_key}"
})
def _request(self, endpoint, method="GET", **kwargs):
"""Lav request med retry-logik."""
url = f"{self.base_url}{endpoint}"
for attempt in range(3):
response = self.session.request(method, url, **kwargs)
if response.status_code == 429:
# Rate limited — vent og prøv igen
ventetid = 2 ** attempt
time.sleep(ventetid)
continue
response.raise_for_status()
return response.json()
raise Exception("Maks antal forsøg overskredet")
def hent_virksomhed(self, cvr_nummer):
"""Hent stamdata for en dansk virksomhed."""
return self._request(f"/dk/company/{cvr_nummer}")
def hent_regnskab(self, cvr_nummer):
"""Hent regnskabsdata (kræver Business+)."""
return self._request(f"/dk/company/{cvr_nummer}/accounts")
def hent_kontakter(self, cvr_nummer):
"""Hent cached kontakter (kræver Business+)."""
return self._request(f"/contacts/{cvr_nummer}")
def hent_norsk_virksomhed(self, orgnr):
"""Hent data for en norsk virksomhed."""
return self._request(f"/no/company/{orgnr}")
# Brug
if __name__ == "__main__":
client = DataCvrClient("DIN_API_NØGLE")
# Hent virksomhedsdata med owners
virksomhed = client.hent_virksomhed("44474117")
print(f"Navn: {virksomhed['name']}")
print(f"Status: {virksomhed['status']}")
print(f"Branche: {virksomhed['industry_description']}")
print(f"Reklamebeskyttet: {virksomhed['protected']}")
for owner in virksomhed.get("owners", []):
print(f" Ejer: {owner['name']} — {owner['role']}")
# Hent ændrede virksomheder (changed feed)
aendrede_dk = client._request("/dk/changed/list/company?since=2026-04-02&limit=10")
print(f"DK ændringer: {aendrede_dk['total']}")
aendrede_no = client._request("/no/changed/list/company?since=2026-04-02&limit=10")
print(f"NO ændringer: {aendrede_no['total']}")
# Hent regnskab
regnskab = client.hent_regnskab("44474117")
seneste = regnskab["accounts"][0]
print(f"Omsætning: {seneste['income_statement']['revenue']} DKK")
PHP integration
PHP bruges stadig bredt i webapplikationer og e-handelsplatforme. Her er en integration med cURL:
<?php
// DataCvrClient.php — PHP CVR-klient
class DataCvrClient {
private string $apiKey;
private string $baseUrl = 'https://datacvrapi.dk/api/v2';
public function __construct(string $apiKey) {
$this->apiKey = $apiKey;
}
private function request(string $endpoint, string $method = 'GET', ?array $body = null): array {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->baseUrl . $endpoint,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . $this->apiKey,
'Content-Type: application/json',
],
CURLOPT_TIMEOUT => 30,
]);
if ($method === 'POST' && $body) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
}
// Retry-logik
$maxForsøg = 3;
for ($i = 0; $i < $maxForsøg; $i++) {
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($httpCode === 429) {
// Rate limited — vent og prøv igen
sleep(pow(2, $i));
continue;
}
break;
}
curl_close($ch);
if ($httpCode >= 400) {
throw new Exception("API fejl: HTTP {$httpCode}");
}
return json_decode($response, true);
}
public function hentVirksomhed(string $cvr): array {
return $this->request("/dk/company/{$cvr}");
}
public function hentRegnskab(string $cvr): array {
return $this->request("/dk/company/{$cvr}/accounts");
}
public function hentKontakter(string $cvr): array {
return $this->request("/contacts/{$cvr}");
}
}
// Brug
$client = new DataCvrClient('DIN_API_NØGLE');
$virksomhed = $client->hentVirksomhed('44474117');
echo "Navn: " . $virksomhed['name'] . "\n"; // "Branthiq ApS"
echo "Status: " . $virksomhed['status'] . "\n"; // "NORMAL"
echo "Beskyttet: " . ($virksomhed['protected'] ? 'Ja' : 'Nej') . "\n";
foreach ($virksomhed['owners'] ?? [] as $owner) {
echo " Ejer: {$owner['name']} — {$owner['role']}\n";
}
$regnskab = $client->hentRegnskab('44474117');
$seneste = $regnskab['accounts'][0];
echo "Omsætning: " . $seneste['income_statement']['revenue'] . " DKK\n";
?>
C# / .NET integration
C# er populært til enterprise-løsninger og Windows-applikationer. Her er en integration med HttpClient:
// DataCvrClient.cs — C# CVR-klient
using System.Net.Http.Headers;
using System.Text.Json;
public class DataCvrClient : IDisposable
{
private readonly HttpClient _httpClient;
private const string BaseUrl = "https://datacvrapi.dk/api/v2";
public DataCvrClient(string apiKey)
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", apiKey);
}
public async Task<JsonDocument> HentVirksomhed(string cvr)
{
var response = await _httpClient.GetAsync(
$"{BaseUrl}/dk/company/{cvr}"
);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(json);
}
public async Task<JsonDocument> HentRegnskab(string cvr)
{
var response = await _httpClient.GetAsync(
$"{BaseUrl}/dk/company/{cvr}/accounts"
);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return JsonDocument.Parse(json);
}
public void Dispose()
{
_httpClient.Dispose();
}
}
// Brug
using var client = new DataCvrClient("DIN_API_NØGLE");
var virksomhed = await client.HentVirksomhed("44474117");
var root = virksomhed.RootElement;
Console.WriteLine($"Navn: {root.GetProperty("name").GetString()}");
Console.WriteLine($"Status: {root.GetProperty("status").GetString()}");
Integration med regnskabssystemer
En af de mest værdifulde integrationer er at forbinde DataCVR API med dit regnskabssystem. Her er konceptuelle eksempler for de mest populære danske regnskabssystemer.
e-conomic — Automatisk kundeoprettelse
Med e-conomic og DataCVR API kan du automatisere kundeoprettelse. Når en bruger indtaster et CVR-nummer, hentes virksomhedsdata automatisk og oprettes som kunde i e-conomic.
// e-conomic integration — auto-opret kunde fra CVR
async function opretKundeFraCvr(cvrNummer) {
// 1. Hent virksomhedsdata fra DataCVR API
const cvrData = await fetch(
`https://datacvrapi.dk/api/v2/dk/company/${cvrNummer}`,
{ headers: { 'Authorization': 'Bearer DATACVR_API_KEY' } }
).then(r => r.json());
// 2. Opret kunde i e-conomic
const kundeData = {
name: cvrData.name,
address: cvrData.address.street,
zip: cvrData.address.zipcode,
city: cvrData.address.city,
country: 'DK',
corporateIdentificationNumber: cvrNummer,
vatZone: {
vatZoneNumber: 1 // Danmark
},
customerGroup: {
customerGroupNumber: 1
},
paymentTerms: {
paymentTermsNumber: 1
},
currency: 'DKK'
};
const response = await fetch(
'https://restapi.e-conomic.com/customers',
{
method: 'POST',
headers: {
'X-AppSecretToken': 'E_CONOMIC_APP_TOKEN',
'X-AgreementGrantToken': 'E_CONOMIC_AGREEMENT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(kundeData)
}
);
return response.json();
}
Dinero — CVR-opslag ved fakturering
Dinero-brugere kan integrere CVR-opslag for automatisk udfyldning af kundeoplysninger ved fakturering:
// Dinero integration — CVR-opslag ved fakturering
async function udfyldKundeoplysninger(cvrNummer) {
const cvrData = await fetch(
`https://datacvrapi.dk/api/v2/dk/company/${cvrNummer}`,
{ headers: { 'Authorization': 'Bearer DATACVR_API_KEY' } }
).then(r => r.json());
// Udfyld formularfelter automatisk
document.getElementById('kunde-navn').value = cvrData.name;
document.getElementById('kunde-adresse').value = cvrData.address.street;
document.getElementById('kunde-postnr').value = cvrData.address.zipcode;
document.getElementById('kunde-by').value = cvrData.address.city;
document.getElementById('kunde-cvr').value = cvrNummer;
}
Billy — Auto-udfyld virksomhedsdata
Billy understøtter CVR-opslag via deres egen integration, men du kan bruge DataCVR API til at berige data med regnskabsoplysninger og kontaktinformation, som Billy ikke leverer.
Integration med CRM-systemer
CRM-systemer som HubSpot og Salesforce kan beriges med CVR-data for at holde kundekort opdaterede.
HubSpot — Berig kontakter med CVR-data
// HubSpot integration — berig virksomhedskort
async function berigHubSpotVirksomhed(hubspotCompanyId, cvrNummer) {
// 1. Hent CVR-data
const cvrData = await fetch(
`https://datacvrapi.dk/api/v2/dk/company/${cvrNummer}`,
{ headers: { 'Authorization': 'Bearer DATACVR_API_KEY' } }
).then(r => r.json());
// 2. Opdater HubSpot virksomhedskort
await fetch(
`https://api.hubapi.com/crm/v3/objects/companies/${hubspotCompanyId}`,
{
method: 'PATCH',
headers: {
'Authorization': 'Bearer HUBSPOT_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
properties: {
name: cvrData.name,
address: cvrData.address.street,
zip: cvrData.address.zipcode,
city: cvrData.address.city,
industry: cvrData.industry_description,
numberofemployees: cvrData.employees,
website: cvrData.website
}
})
}
);
}
Webhooks og kontakt-scraping
DataCVR API's kontakt-scraping bruger et asynkront mønster. Du starter et scrape-job, og derefter poller du for resultater:
// Kontakt-scraping — asynkront mønster
async function scrapeKontakter(cvrNummer, apiKey) {
// 1. Start scrape-job
const startResponse = await fetch(
'https://datacvrapi.dk/api/v2/contacts/scrape',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ cvr_number: cvrNummer })
}
);
if (startResponse.status !== 202) {
throw new Error('Kunne ikke starte scrape-job');
}
const { job_id } = await startResponse.json();
// 2. Poll for resultater (max 2 minutter)
for (let i = 0; i < 24; i++) {
await new Promise(r => setTimeout(r, 5000)); // Vent 5 sekunder
const statusResponse = await fetch(
`https://datacvrapi.dk/api/v2/scrape-jobs/${job_id}`,
{ headers: { 'Authorization': `Bearer ${apiKey}` } }
);
const job = await statusResponse.json();
if (job.status === 'completed') {
return job.contacts; // Array af kontakter
}
if (job.status === 'failed') {
throw new Error(`Scrape fejlede: ${job.error}`);
}
}
throw new Error('Timeout — scrape tog for lang tid');
}
Fejlhåndtering
Robust fejlhåndtering er afgørende for en stabil integration. Her er de vigtigste scenarier og hvordan du håndterer dem:
Retry-logik med exponential backoff
// Generisk retry-funktion
async function medRetry(fn, maxForsøg = 3) {
for (let i = 0; i < maxForsøg; i++) {
try {
return await fn();
} catch (error) {
if (i === maxForsøg - 1) throw error;
// Exponential backoff: 1s, 2s, 4s
const ventetid = Math.pow(2, i) * 1000;
console.log(`Forsøg ${i + 1} fejlede, prøver igen om ${ventetid}ms...`);
await new Promise(r => setTimeout(r, ventetid));
}
}
}
// Brug med CVR-opslag
const virksomhed = await medRetry(() =>
hentVirksomhed('44474117')
);
Håndtering af specifikke fejlkoder
async function sikkertCvrOpslag(cvrNummer) {
const response = await fetch(
`https://datacvrapi.dk/api/v2/dk/company/${cvrNummer}`,
{ headers: { 'Authorization': 'Bearer DIN_API_NØGLE' } }
);
switch (response.status) {
case 200:
return await response.json();
case 400:
throw new Error('Ugyldigt CVR-nummer — skal være 8 cifre');
case 401:
throw new Error('Ugyldig API-nøgle — tjek din nøgle i dashboardet');
case 403:
throw new Error('Dit abonnement giver ikke adgang til dette endpoint');
case 404:
throw new Error('Virksomheden findes ikke i CVR-registret');
case 429:
throw new Error('Rate limit overskredet — prøv igen senere');
default:
throw new Error(`Uventet fejl: ${response.status}`);
}
}
Best practices
Følg disse anbefalinger for en optimal integration:
Caching
Virksomhedsdata ændrer sig sjældent. Cache resultater lokalt i mindst 1 time (eller 24 timer for stamdata) for at reducere API-kald og forbedre responstider i din applikation.
Batch-opslag
Hvis du skal slå mange virksomheder op, implementer en kø der sender requests sekventielt med en kort pause imellem. Det undgår rate limiting og sikrer pålidelig datahentning.
Fejlhåndtering
Implementer altid retry-logik med exponential backoff for at håndtere midlertidige fejl og rate limiting. Log fejl, så du kan identificere og løse problemer hurtigt.
Miljøvariabler
Gem aldrig din API-nøgle i kildekoden. Brug miljøvariabler (process.env.DATACVR_API_KEY i Node.js, os.environ i Python) til at holde nøglen sikker.
Validering
Validér CVR-numre (8 cifre, modulus 11) på klientsiden, inden du sender requests til API'et. Det sparer API-kald og giver hurtigere feedback til brugeren.