CVR Opslag Priser Dokumentation Kontakt
Log ind Kom i gang

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:

  1. Gratis konto: Opret en konto på datacvrapi.dk (tager under 1 minut)
  2. API-nøgle: Find din API-nøgle i dit dashboard under "API-nøgle"
  3. 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.

Ofte stillede spørgsmål om CVR API integration

Hvordan integrerer jeg CVR API?

Opret en gratis konto, find din API-nøgle i dashboardet, og lav HTTP-kald til vores REST API. Data returneres som JSON, der nemt integreres i alle sprog.

Hvilke programmeringssprog understøttes?

Alle sprog der kan lave HTTP-kald. Vi har kodeeksempler i JavaScript, Python, PHP og C#/.NET, men API'et virker med alle sprog og frameworks.

Kan jeg integrere med e-conomic?

Ja, du kan kombinere DataCVR API med e-conomic's REST API for automatisk kundeoprettelse med CVR-data. Se kodeeksemplet ovenfor.

Hvordan håndterer jeg rate limiting?

Implementer retry-logik med exponential backoff. Vent 1s efter første 429-svar, fordobl for hvert forsøg (2s, 4s). Cache desuden resultater lokalt.

Er der SDK'er tilgængelige?

Vi arbejder på officielle SDK'er til JavaScript/TypeScript og Python. Indtil da kan kodeeksemplerne i denne guide bruges som udgangspunkt.

Klar til at integrere CVR-data i dit system?

Opret en gratis konto og lav dit første API-kald på under 2 minutter.