DataCVR API giver nem adgang til danske virksomhedsdata via en moderne REST API. Uanset om du skal integrere CVR-opslag i dit regnskabssystem, bygge en leadgenereringsplatform, eller automatisere compliance-processer, så giver API'et dig de data, du har brug for - hurtigt og i struktureret JSON-format.
Kom i gang
Det tager under 2 minutter at komme i gang med DataCVR API. Følg disse tre trin:
- Opret en gratis konto på datacvrapi.dk/opret-konto
- Find din API-nøgle i dit dashboard under "API-nøgle"
- Lav dit første kald med din API-nøgle som autentificering
Den gratis plan giver dig 25 opslag per dag - nok til at teste og komme i gang.
Autentificering
Scripts og integrationer skal sende en API-nøgle. Uden nøgle afvises kendte script-klienter (fx curl, python-requests, axios og node-fetch) med 401 API_KEY_REQUIRED. Et kald uden nøgle fra en almindelig browser får et begrænset anonymt opslag: 25 om dagen pr. IP-adresse. Du kan autentificere på tre måder:
1. Bearer Token (anbefalet)
Authorization: Bearer DIN_API_NØGLE
2. X-API-Key Header
X-API-Key: DIN_API_NØGLE
3. Basic Auth
Authorization: Basic base64(DIN_API_NØGLE:)
API-nøglen som brugernavn, tomt password. Eksempel med curl: curl -u "DIN_API_NØGLE:"
Vigtigt: En nøgle i query string (fx ?api_key=) bliver ikke læst, så kaldet behandles som et kald uden nøgle: et script får 401 API_KEY_REQUIRED, og en browser får det anonyme opslag. Send altid nøglen i en header eller med Basic Auth.
Base URL
API'et er tilgængeligt via to identiske base-URLs. Begge peger på samme backend, og du kan frit bruge den du foretrækker:
https://datacvrapi.dk/api/v2 (kanonisk, anbefalet)
https://api.datacvrapi.dk/api/v2 (subdomain-alias)
Eksempel: GET /dk/company/10150817 kan kaldes via https://datacvrapi.dk/api/v2/dk/company/10150817 eller https://api.datacvrapi.dk/api/v2/dk/company/10150817. Samme svar.
Vi anbefaler datacvrapi.dk/api/v2 i ny kode. api.datacvrapi.dk eksisterer som alias for bagudkompatibilitet. Bemærk at stien altid starter med /api/v2/, også på api.-subdomainet.
Alle endpoints bruger HTTPS (TLS 1.2+) for sikker kommunikation.
Endpoints oversigt
API'et er opdelt i tre tydelige områder:
- Danske virksomheder: CVR-data fra Erhvervsstyrelsen. Sti-prefix:
/dk/ - Norske virksomheder: Organisationsdata fra Brønnøysundregistrene. Sti-prefix:
/no/ - Scrape tokens (tilkøb): Kontakt-scraping fra virksomhedens hjemmeside. Betales med separate scrape-tokens og kræver Hobby eller højere. Sti:
/account/scrape-tokens+ scrape-endpoints på virksomheder
Derudover findes et public uptime-endpoint GET /api/v2/health (ingen API-nøgle, ingen rate-limit), som returnerer {"status":"ok","version":"v2","timestamp":"..."}. Beregnet til monitorer og deploy smoke-tests.
Til SLA-monitoring findes også et deep health-endpoint GET /api/v2/health/deep, som verificerer database, Erhvervsstyrelsens ES API, og delta-sync freshness. Returnerer HTTP 503 hvis database eller ES API er utilgængelig.
Historikken bag statussiden står på GET /api/v2/health/history (ingen API-nøgle): oppetid og de seneste målinger for 24 timer eller 7 dage (?period=7d).
AI-integration (nyt): GET /api/v2/ai/tools returnerer OpenAI function-calling JSON med de 6 primære endpoints. Ingen API-nøgle kræves. Bruges af ChatGPT plugins, Cursor og andre LLM-klienter til auto-discovery af API'et. Alle company-responses indeholder nu et llm_summary-felt med en kort prosa-opsummering.
MCP-server: Den officielle MCP-server @datacvrapi/mcp giver Claude Desktop, Claude Code, Codex, Cursor og VS Code direkte adgang til API'et med 10 tools: søgning, virksomhedsopslag, ejere, person-opslag, P-numre og regnskaber for både Danmark og Norge. Den kører lokalt via npx og bruger din egen API-nøgle. Se opsætningsguiden.
Danske virksomheder (/dk/)
Plan-kolonnen viser den laveste plan der giver adgang. Alle højere planer har også adgang. Regnskabsdata er med fra Business, koncern-grafen kræver Business+.
| Endpoint | Metode | Beskrivelse | Plan |
|---|---|---|---|
/dk/company/{cvr} |
GET | Stamdata fra CVR (navn, adresse, status, branche, ejere) | Gratis |
/dk/live/company/{cvr} |
GET | Stamdata hentet direkte fra CVR; svaret gemmes også i vores kopi, medmindre du sender ?save=false (kræver API-nøgle) |
Gratis |
/dk/live/search |
GET | Søgning direkte i CVR i stedet for vores kopi (kræver API-nøgle) | Gratis |
/dk/live/import/{cvr} |
POST | Henter en virksomhed fra CVR ind i vores kopi, fx en helt ny (kræver API-nøgle) | Gratis |
/dk/search/company |
GET | Søg virksomheder (navn, branche, status, by, postnummer) | Alle |
/dk/suggestions/company/{query} |
GET | Autocomplete på virksomhedsnavn | Alle |
/dk/industry/counts |
GET | Antal virksomheder per branchekode | Alle |
/dk/subsidiary/{pnr} |
GET | P-nummer opslag (produktionsenhed) | Alle |
/dk/search/subsidiary |
GET | Søg produktionsenheder | Alle |
/dk/suggestions/subsidiary/{query} |
GET | Autocomplete på P-nummer | Alle |
/dk/participant/{id} |
GET | Opslag på en person i ejerkreds eller ledelse: navn, postnummer, by og roller (kræver API-nøgle) | Alle |
/dk/search/participant |
GET | Søg personer i ejerkreds og ledelse på navn (kræver API-nøgle, se nedenfor) | Alle |
/dk/suggestions/participant/{query} |
GET | Autocomplete på personers navn, mindst 3 tegn (kræver API-nøgle) | Alle |
/dk/changed/list/company |
GET | Ændrede DK virksomheder (changed feed) | Alle |
/dk/changed/company/{cvr} |
GET | Hvornår virksomheden sidst blev opdateret hos os: {vat, last_changed} |
Alle |
/dk/company/{cvr}/structure |
GET | Koncernstruktur: moder- og datterselskaber med ejerandele | Gratis |
/dk/company/{cvr}/graph |
GET | Fuldt koncern-træ (moder-kæde og datterselskaber) med regnskabstal. ?format=svg giver et renderet SVG-fragment |
Business+ |
/dk/company/{cvr}/accounts |
GET | Regnskaber for virksomheden, nyeste først (standard 10, højst 100 med ?limit=). Listen kan indeholde kvartals- og halvårsrapporter, som kendes på document_type |
Business |
/dk/company/{cvr}/accounts/latest |
GET | Seneste årsregnskab (helår) for virksomheden | Business |
/dk/search/accounts |
GET | Søg i regnskabsdata | Business |
/dk/company/{cvr}/capital-changes |
GET | Detaljerede kapitalændringer med kurs, indbetalingsmåde og beslutningsdato. Samme kilde som capital-changes-live, men svaret caches i 30 dage |
Hobby+ |
/dk/company/{cvr}/capital-changes/contribute |
POST | Bidrag rå HTML fra virk.dk registreringsmeddelelser så data kan parses og caches (max 50/dag/bruger) | Business |
/dk/company/{cvr}/capital-changes-live |
GET | Live kapitalændringer fra Erhvervsstyrelsens registreringstekster API | Hobby+ |
/dk/company/{cvr}/address-changes |
GET | Adresse- og hjemstedsændringer historik | Hobby+ |
/dk/company/{cvr}/personnel-changes |
GET | Direktion, bestyrelse, tilsynsråd, tegningsberettigede (med enhedsNummer-link til personer) |
Hobby+ |
/dk/company/{cvr}/auditor-changes |
GET | Revisor-skift (fratrådte/tiltrådte med CVR + adresse) | Hobby+ |
/dk/company/{cvr}/status-changes |
GET | Konkurs, opløsning, tvangsopløsning, likvidation, rekonstruktion | Hobby+ |
/dk/company/{cvr}/founding-text |
GET | Fuld stiftelsestekst med stiftere, direktion, bestyrelse, kapital, formål | Hobby+ |
/dk/company/{cvr}/mergers-demergers |
GET | Fusioner og spaltninger (offentliggjort + gennemført, parties med rolle) | Hobby+ |
/dk/company/{cvr}/conversions |
GET | Selskabsomdannelser (ApS→A/S, IVS→ApS, ...) | Hobby+ |
/dk/company/{cvr}/owner-discrepancies |
GET | Uoverensstemmelser i reelle ejere | Hobby+ |
/dk/company/{cvr}/corrections |
GET | Erhvervsstyrelsens rettelser til tidligere registreringer | Hobby+ |
/dk/company/{cvr}/other-registrations |
GET | Vedtægtsændringer, formålsændringer, øvrige | Hobby+ |
/dk/company/{cvr}/registreringstekster |
GET | Raw registreringstekster (alle 12 status-typer, med filter ?status=) |
Hobby+ |
Registreringstekster (officiel Erhvervsstyrelsen-data)
De 12 endpoints under /dk/company/{cvr}/ der ender på -changes, -text, conversions, corrections, mergers-demergers, owner-discrepancies, other-registrations og registreringstekster leverer struktureret data fra Erhvervsstyrelsens officielle CVR-historik (distribution.virk.dk/registreringstekster).
Adgang verificeret via system-til-system aftale med Erhvervsstyrelsen (sagsnr. 146615).
Samlet quota for alle registreringstekst-endpoints: 100/30d (Hobby), 1.000/30d (Business).
Personer leveres med enhedsNummer så du kan slå dem op i /dk/participant/{enhedsNummer}.
Virksomheder leveres med 8-cifret CVR + adresse når nævnt i original-teksten.
Norske virksomheder (/no/)
Data hentes fra Brønnøysundregistrene (brreg.no) og har tilsvarende struktur som danske endpoints. Organisationsnummer er 9 cifre.
/no/ via samme path-struktur. Ikke alle datatyper er dog tilgængelige i Norge: registreringstekster (stiftelsestekst, kapitalændringer-live, person- og adresseændringer, fusioner/spaltninger og resten af /registreringstekster-familien) findes kun på /dk/, da Brønnøysundregistrene ikke offentliggør tilsvarende historiske registreringsdokumenter. Norske felter kan også afvige (fx ingen companystatus_code-mapping; NO bruger egen AKTIV/OPPLOEST-klassifikation).
| Endpoint | Metode | Beskrivelse | Plan |
|---|---|---|---|
/no/company/{orgnr} |
GET | Stamdata for norsk virksomhed | Gratis |
/no/search/company |
GET | Søg norske virksomheder | Alle |
/no/changed/list/company |
GET | Ændrede NO virksomheder (changed feed) | Alle |
/no/changed/list/company/{updateId} |
GET | Ændrede NO virksomheder fra et bestemt updateId i Brønnøysund | Alle |
/no/company/{orgnr}/accounts |
GET | Norske regnskaber | Business |
/no/company/{orgnr}/accounts/latest |
GET | Seneste norske regnskab (koncernregnskabet, når begge findes) | Business |
Scrape tokens (tilkøb)
Kontakt-scraping henter telefon, email og direktør-kontaktinfo fra virksomhedens hjemmeside. Det er en separat tilkøbsydelse der betales med scrape-tokens (1 token per scrape-job, uanset udfald). Tokens købes som engangskøb i dashboardet, men kontakt-scraping kræver Hobby eller højere.
Flow: (1) POST /dk/company/{cvr}/contacts/scrape starter et job → (2) poll GET /dk/company/{cvr}/scrape-jobs/{id} for status → (3) hent resultat via GET /dk/company/{cvr}/contacts når færdig. Resultat caches 30 dage.
| Endpoint | Metode | Beskrivelse | Omkostning |
|---|---|---|---|
/account/scrape-tokens |
GET | Samme som /account/scrape-tokens/balance |
Gratis |
/account/scrape-tokens/balance |
GET | Tjek token-saldo | Gratis |
/account/scrape-tokens/history |
GET | Historik over køb og forbrug af tokens | Gratis |
/account/scrape-tokens/packages |
GET | Pakker med tokens og priser i kr. | Gratis |
/account/scrape-tokens/buy |
POST | Starter et køb af tokens og svarer med en adresse til Stripes betalingsside | Gratis, kræver Hobby eller højere |
/dk/company/{cvr}/contacts/scrape |
POST | Start scrape-job for virksomhed | 1 token |
/dk/contacts/bulk |
POST | Starter kontakt-scraping for op til 50 CVR-numre på én gang | 1 token pr. CVR, kræver Business, Enterprise eller Custom |
/dk/company/{cvr}/scrape-jobs/{id} |
GET | Tjek scrape-job status (pending/running/completed/failed) | Gratis |
/dk/company/{cvr}/scrape-jobs/{id} |
PATCH | Annullerer et job, der stadig venter, og giver tokenet tilbage | Gratis |
/dk/company/{cvr}/contacts |
GET | Hent cached kontakter fra tidligere scrape | Gratis (cached 30 dage) |
Response format
Alle endpoints returnerer JSON. Her er eksempler på de mest brugte endpoints. Svarene er hentet 06-10-2026. Svaret for Novo Nordisk er forkortet: en del felter er udeladt, og listerne over ejere, produktionsenheder og ansatte viser kun én post.
Virksomhedsdata (stamdata)
GET /api/v2/dk/company/24256790
{
"vat": 24256790,
"name": "NOVO NORDISK A/S",
"address": "Novo Alle 1",
"zipcode": "2880",
"city": "Bagsværd",
"cityname": "Bagsværd",
"protected": false,
"phone": "44448888",
"email": null,
"fax": null,
"startdate": "1931-11-28",
"enddate": null,
"employees": "5000+",
"industrycode": 212000,
"industrydesc": "Fremstilling af farmaceutiske præparater",
"companycode": 60,
"companydesc": "A/S",
"website": null,
"companystatus": "Aktiv",
"creditbankrupt": false,
"address_details": {
"street": "Novo Alle",
"house_number": "1",
"floor": null,
"door": null,
"co_name": null,
"zipcode": "2880",
"city": "Bagsværd",
"municipality": "GLADSAXE",
"municipality_code": 159,
"country": "DK",
"latitude": null,
"longitude": null
},
"owners": [
{
"name": "Novo Holdings A/S (CVR 24257630)",
"role": "LEGAL EJER",
"title": "EJERREGISTER",
"share": 25,
"startdate": "2000-11-13",
"enddate": null,
"active": true
}
],
"signing_rule": "Selskabet forpligtes ved underskrift (i) af to direktører i forening, (ii) af en direktør eller et bestyrelsesmedlem i forening med bestyrelsens formand eller næstformand eller (iii) af den samlede bestyrelse.",
"productionunits": [
{"pno": 1006455042, "startdate": "1931-11-28", "enddate": null}
],
"lifecycle": [
{"startdate": "1931-11-28", "enddate": null}
],
"companyform_history": [
{"code": 60, "short": "A/S", "long": "Aktieselskab", "startdate": "1931-11-28", "enddate": null}
],
"employees_yearly": [
{"year": 2018, "employees": "1000-999999", "employees_exact": 16125, "fte": 16466}
],
"llm_summary": "NOVO NORDISK A/S (CVR 24256790) er en virksomhed inden for Fremstilling af farmaceutiske præparater fra Bagsværd. Stiftet 1931, status Aktiv, over 5.000 ansatte.",
"t": 1791272382,
"version": 8
}
name- Personens eller selskabets navn.LEGAL EJERvises som "Navn (CVR 12345678)", når ejeren er et dansk selskab. Er ejeren en person eller et udenlandsk selskab, står kun navnet, og CVR's enhedsnummer står iparticipantnumberrole- Funktionen, som CVR registrerer den, fx ADM. DIR., DIREKTØR, FORMAND, BESTYRELSESMEDLEM eller SUPPLEANT. Ejere fra CVR's ejerregister harLEGAL EJERellerREEL EJER.REEL EJERdækker personer eller udenlandske selskaber uden dansk CVR, registreret i CVR's ejerregister (legale ejere med mindst 5 %), fx et engelsk Limited-selskab. Det er ikke reelle ejere efter hvidvaskloven: de offentliggøres ikke i CVR siden 01-09-2025 (Erhvervsstyrelsen) og leveres ikke af API'ettitle- Organisationen i CVR, fx Direktion, Bestyrelse eller EJERREGISTERshare- Ejerandel i procent (null hvis ikke relevant)participantnumber- Deltager-nummer til person-opslag via/participant/{id}startdate/enddate- Rolleperiode (enddate=null = aktiv)active- Boolean.true= aktiv rolle,false= ophørt. Listen indeholder også ophørte ejere og roller, så filtrér påactive: true, når du vil se de nuværende
REEL EJER og som LEGAL EJER, og begge poster har det samme participantnumber. Filtrér på active: true først, og fjern så dubletter på participantnumber, før du lægger andelene sammen. For RISIKA A/S (CVR 37677892) bliver summen af share ellers 95 % i stedet for 75 %. Før 06-10-2026 stod enhedsnummeret som "(CVR …)" i navnet på LEGAL EJER-postenVigtig: Ejere hentes live fra CVR-registret ved hvert opslag. Ved midlertidigt nedetid på datakilde kan owners være tomt. protected - Boolean.
true = virksomheden er reklamebeskyttet (markedsføringsforbudslisten). Brug dette felt til at afgøre marketing eligibility.
/dk/search/participant?name=) søger på navn blandt personer i ejerkreds og ledelse i CVR. Søgningen kræver en API-nøgle og spørger CVR direkte. En søgning tæller som ét opslag på kvoten, som en virksomhedssøgning.
name- Påkrævet, mindst 2 bogstaver og højst 100 tegn. Alle ord skal stå i personens nuværende navn, i vilkårlig rækkefølgelimit- 1 til 25, standard 10.offset- standard 0.offset + limitmå højst være 3.000, som er CVR's grænse. Er der flere end 3.000 træf, kan du kun hente de første 3.000, så gør navnet mere præcist- Svaret har
total,limit,offsetogresults[]medparticipantnumber,type(altidperson),nameogactive_roles. Det er antallet af aktive roller, talt efter samme regel somactivei/dk/participant/{participantnumber}, hvor du ser rollerne - Svaret har ingen adresse og intet CPR-nummer. Opslaget på
/dk/participant/{participantnumber}giver postnummer og by, men ikke gadeadressen - Søgningen finder personer, som CVR stadig opdaterer: med en aktiv rolle eller en rolle, der er ophørt inden for de seneste 5 år. Personer uden for den gruppe kan stadig slås op på
participantnumber, fx fra en virksomhedsowners - Højst 300 søgninger og forslag pr. konto over 24 timer. Derefter svares 429
PERSON_SEARCH_LIMIT - Personer, der har gjort indsigelse hos os, vises ikke, så søgningen er ikke udtømmende
vat,roleogzipcodeunderstøttes ikke og giver 400.participant_typemå kun væreperson- Kun Danmark.
/no/search/participantgiver 400UNSUPPORTED_COUNTRY
/dk/suggestions/participant/{navn}) kræver mindst 3 bogstaver og en API-nøgle. Det sidste ord må være begyndelsen af et navn, fx lars han. Svaret er suggestions[] med participantnumber, type og name. limit er 1 til 20, standard 10. Listen er ikke udtømmende. Hvert forslag tæller som et opslag, så vent til brugeren holder en pause i skrivningen, før du spørger.Fejl: 401 uden nøgle, 400 ved ugyldige parametre, 429 ved loftet, 503 hvis vi ikke kan tjekke indsigelserne, og 502 hvis CVR ikke svarer. Svar med resultater sendes med
Cache-Control: private, no-store.
status_history[]- Alle statusændringer (status,startdate,enddate)name_history[]- Navneændringer (name,startdate,enddate)address_history[]- Adresseændringer (address,zipcode,city,municipality,startdate,enddate)industry_history[]- Brancheændringer (code,text,startdate,enddate)purpose_history[]- Formålsændringer (purpose,startdate,enddate)capital_history[]- Kapitalændringer (capital,currency,startdate,enddate)companyform_history[]- Virksomhedsform over tid. Fx IVS → ApS → A/Semployees_monthly[]- Ansatte pr. måned (year,month,employees,fte)employees_quarterly[]- Ansatte pr. kvartalemployees_yearly[]- Ansatte pr. år
employees_yearly i 2018, mens employees_monthly går til juli 2026 (hentet 06-10-2026). Listerne er sorteret ældst først, så den nyeste post er den sidste.
Alle historik-felter inkluderer startdate/enddate perioder. employees er et interval (fx "10-19") eller eksakt tal. fte er fuldtidsækvivalenter. Data stammer direkte fra CVR-registret og opdateres dagligt.
address_details- Struktureret adresse medstreet,house_number,floor,door,co_name,municipality,municipality_codesigning_rule- Tegningsregel (fx "Selskabet tegnes af en direktør")signing_rule_history[]- Historik for tegningsregelauditors[]- Revisorer medname,startdate,enddatefounders[]- Stiftereproductionunits[]- Produktionsenheder medpno(P-nummer),startdateogenddate. Adresse, branche og ansatte for en P-enhed hentes via/dk/subsidiary/{pnr}mergers_demergers[]- Fusions- og spaltningsdatafiscal_year- Regnskabsårets start/slutarticles_date- Seneste vedtægtsdatoowners[].participantnumber- Deltager-nummer til person-opslag via/participant/{id}
equity_ratio, return_on_equity, liquidity_ratio, solvency_ratio, debt_ratio) beregnes per regnskabsår og returneres i /company/{cvr}/accounts endpointet.
Regnskabsdata
Felterne, eksempler og hvad regnskaberne dækker: Regnskab API. Henter du i dag fra Virk direkte, så se CVR API eller Virk.
GET /api/v2/dk/company/35954716/accounts/latest
{
"cvr": "35954716",
"report_id": "urn:ofk:oid:39142125",
"document_type": "aarsrapport",
"period_start": "2025-01-01",
"period_end": "2025-12-31",
"fiscal_year": 2025,
"publication_date": "2026-04-29T12:56:16.440Z",
"currency": "DKK",
"figures": {
"revenue": 83168000000,
"gross_profit": 24639000000,
"operating_profit": 3245000000,
"profit_before_tax": 2583000000,
"net_profit": 1990000000,
"total_assets": 53265000000,
"fixed_assets": 41466000000,
"current_assets": 11799000000,
"cash": 1320000000,
"equity": 15762000000,
"total_liabilities": 53265000000,
"provisions": 107000000,
"long_term_debt": 20510000000,
"short_term_debt": 16993000000,
"equity_ratio": 29.59,
"return_on_equity": 12.63,
"liquidity_ratio": 0.69,
"solvency_ratio": 29.59,
"debt_ratio": 2.38
},
"xbrl_url": "http://regnskaber.virk.dk/61745953/...xml",
"ixbrl_url": "http://regnskaber.virk.dk/61745953/...xhtml"
}
Svaret er hentet 06-10-2026. Alle beløb er i DKK. Liste-endpointet (/accounts) returnerer { cvr, count, accounts: [...] }, nyeste periode først; /accounts/latest returnerer det seneste helårsregnskab som et nøgent objekt. Listen kan også indeholde halvårs- og kvartalsrapporter. De har document_type "halvaarsrapport" eller "delaarsrapport", mens årsregnskaber har "aarsrapport" (før 06-10-2026 stod alle som "aarsrapport"). Sjældnere typer fra Virk kommer igennem med små bogstaver, fx "undtagelseserklaering". Brug /accounts/latest, når du skal bruge årsregnskabet. Parseren er namespace-agnostisk: håndterer både Danish GAAP (fsa:) og IFRS (ifrs-full:) taxonomier samt alle namespace-aliaser (xbrli:xbrl, xi:xbrl, ix:xbrl, m.fl.). Op til 15 rapporterede tal (de 14 i eksemplet og employees, når regnskabet oplyser antal ansatte) + 5 beregnede nøgletal (equity_ratio, return_on_equity, liquidity_ratio, solvency_ratio, debt_ratio). Felter uden værdi udelades helt i stedet for at stå som null.
Gældsgrad: debt_ratio = (total_liabilities - equity) / equity. I danske regnskaber er total_liabilities passiver i alt (XBRL LiabilitiesAndEquity), altså gæld plus egenkapital, så tælleren er gælden. I eksemplet, i mio. kr.: (53.265 - 15.762) / 15.762 = 2,38. I norske regnskaber er total_liabilities gæld i alt (Brønnøysundregistrenes sumGjeld), så debt_ratio er total_liabilities / equity med højst tre decimaler. Når egenkapitalen er 0 eller negativ (eller den norske gæld er negativ), udelades gældsgraden i danske regnskaber og er null i norske.
Dokumentlinks: xbrl_url og ixbrl_url peger på regnskabsfilerne hos Erhvervsstyrelsen (gratis, ingen auth). pdf_url kommer kun med, når Erhvervsstyrelsen har en PDF til regnskabet, og ellers er feltet udeladt.
Tomme figures? Hvis et regnskab returneres med figures: {}, kontakt support med CVR + fiscal_year. Parseren dækker alle kendte XBRL-namespace-varianter, men nye taxonomi-aliaser kan opstå over tid og kræver opdatering af parserens whitelist.
Norske regnskaber returneres med afvigende figures. Brønnøysundregistrene leverer ofte både koncernregnskab (report_type: "KONSERN") og selskabsregnskab ("SELSKAP") for samme år, så filtrér på report_type, før du sammenligner år. /accounts/latest giver koncernregnskabet, når begge findes. fiscal_year er året for period_end. total_liabilities er gæld i alt, ikke passiver i alt som i Danmark. NO inkluderer long_term_debt, men mangler gross_profit, profit_before_tax, cash, employees, provisions, equity_ratio og return_on_equity. Valutaen står i currency, som regel NOK, men nogle koncerner indberetter i fx USD. PDF/XBRL/iXBRL-felter findes ikke for norske regnskaber.
Error codes: 400 INVALID_CVR, 400 INVALID_PARAMETER (limit ikke positivt heltal), 403 TIER_REQUIRED (Business eller højere påkrævet; det gælder også kald uden nøgle), 404 NOT_FOUND (ingen regnskaber for CVR), 502 UPSTREAM_ERROR.
Detaljerede kapitalændringer
Komplet kapitalhistorik per dansk virksomhed med kurs, beslutningsdato, vedtægtsdato og indbetalingsmetode. Tier: Hobby (100 pr. 30 dage inkl.) eller Business (1.000 pr. 30 dage inkl.). Kun for danske virksomheder.
GET /api/v2/dk/company/36424303/capital-changes
{
"cvr": "36424303",
"count": 8,
"capital_changes": [
{
"registered_date": "2026-02-20",
"change_type": "AENDRING_KAPITAL",
"direction": "increase",
"company_name": "Dripdrop ApS",
"address": "Søren Frichs Vej 25, 1., 8000 Aarhus C",
"statutes_changed_date": "2026-02-06",
"decision_date": "2026-02-06",
"execution_date": null,
"amount": 1400,
"currency": "DKK",
"payment_method": "kontant",
"exchange_rate": 7437.14,
"tranches": [
{ "amount": 1400, "exchange_rate": 7437.14, "payment_method": "kontant" }
],
"share_classes": null,
"capital_after": 97414.12,
"is_correction": false
}
],
"data_available": true,
"source": "distribution.virk.dk/registreringstekster",
"cached_at": "2026-10-01T02:00:49.073+00:00",
"expires_at": "2026-10-31T21:57:11.138+00:00",
"status": "ok",
"_meta": {
"feature_status": "live",
"source_description": "Officiel ElasticSearch-adgang til Erhvervsstyrelsens registreringstekster (sagsnr. 146615). Svar caches i 30 dage.",
"quota": {
"limit_per_30_days": 1000,
"used_this_period": 87,
"remaining": 913,
"tier": "business"
}
}
}
Status-koder: ok (data leveret), pending (cachen er udløbet, og kilden svarede ikke ved seneste forsøg, så du får den seneste kendte version), error (kilden svarede ikke, og der er intet i cachen; data_available er false).
Kilde: Data hentes via vores officielle system-til-system adgang til Erhvervsstyrelsens registreringstekster (sagsnr. 146615) og caches i 30 dage. En virksomhed, der ikke er i cachen, hentes, når du spørger. Quota: Hvis du når grænsen for de seneste 30 dage, returneres HTTP 429 CAPITAL_QUOTA_EXCEEDED, og Retry-After angiver sekunder til næste ledige opslag.
Søg virksomheder
total_estimated er true, når total er et skøn og ikke et eksakt tal. Det gælder resultatsæt over 1.000 virksomheder. Paginér, til en side har færre end limit resultater. En side efter sidste resultat giver 200 med en tom liste.
GET /api/v2/dk/search/company?name=branthiq&limit=10
{
"total": 1,
"total_estimated": false,
"limit": 10,
"offset": 0,
"results": [
{
"vat": 45786943,
"name": "Branthiq ApS",
"address": "Vesterbrogade 208",
"zipcode": "1800",
"city": "Frederiksberg C",
...
}
]
}
// Søgeparametre. Mindst ét af disse skal med, ellers svarer API'et
// 400 INVALID_QUERY: name, vat, industrycode, zipcode, city, municipality,
// companyform, companystatus, employees_min, employees_max, capital_min,
// capital_max, founded_after, founded_before (og cursor ved paginering).
// De kan kombineres frit.
// name : virksomhedsnavn (partiel match, case-insensitive)
// vat (eller cvr) : CVR-nummer, 8 cifre (eksakt; 9 cifre under /no/). Til ét
// opslag er /dk/company/{cvr} hurtigere og giver ejere med
// zipcode : postnummer (eksakt match)
// city : by (partiel match)
// industrycode : branchekode (DB07), fx "620100" (eksakt) eller "62" (præfiks)
// companyform : virksomhedsform: integer-kode (80) eller forkortelse ("ApS", "A/S", "I/S")
// companystatus : string-label (anbefalet) eller integer-kode:
// "NORMAL" / 20 : aktiv virksomhed
// "AKTIV" / 20 : alias for NORMAL
// "OPLØST" / 3 : opløst (generisk)
// "UNDER KONKURS" / 5 : under konkursbehandling
// "UNDER FRIVILLIG LIKVIDATION" / 6
// "UNDER TVANGSOPLØSNING" / 7
// "OPHØRT" / 8 : ophørt
// "SLETTET" / 3 : slettet
// "UDENRETSVIRKNING" : uden retsvirkning
// (string-labels er case-insensitive, mellemrum ignoreres)
// employees_min, employees_max : antal ansatte
// capital_min, capital_max : selskabskapital i DKK
// founded_after, founded_before : stiftelsesdato (YYYY-MM-DD)
// municipality : kommunekode (fx 101) eller kommunenavn (partiel)
// Ekstra filtre, der kun virker sammen med mindst ét af filtrene ovenfor
// (alene giver de 400 INVALID_QUERY):
// address : adresse (partiel match)
// phone : telefonnummer (partiel match)
// email : email (partiel match)
// Pagination: limit (default 50 med nøgle, 20 anonymt; max 1000 med nøgle),
// offset (max 10000 med nøgle), cursor (alternativ til offset)
// Bemærk: disse parameter-navne findes IKKE. Alene giver de 400 INVALID_QUERY.
// Sammen med et gyldigt filter ignoreres de uden fejl. Den 06-10-2026 gav
// ?city=Aalborg&branche=620100 de samme 6.090 hits som ?city=Aalborg alene:
// branche → brug industrycode
// status → brug companystatus
// region → brug municipality
// website, hasWebsite, ingenHjemmeside → findes ikke som filter
// creditstatus → ikke implementeret som filter
Autosuggest
GET /api/v2/dk/suggestions/company/branthiq
{
"suggestions": [
{ "vat": 45786943, "name": "Branthiq ApS", "address": "Vesterbrogade 208, 1800 Frederiksberg C" }
]
}
Norsk virksomhed (med owners)
GET /api/v2/no/company/923609016
{
"vat": 923609016,
"name": "EQUINOR ASA",
"address": "Forusbeen 50",
"zipcode": "4035",
"city": "STAVANGER",
"companydesc": "Allmennaksjeselskap",
"companystatus": "AKTIV",
"industrydesc": "Utvinning av råolje",
"owners": [
// Listen har også personer med title "Daglig leder" og "Styre"
// (role fx "Styrets leder", "Styremedlem", "Varamedlem"). De er udeladt her.
{
"name": "976389387",
"role": "Revisor",
"title": "Revisor",
"share": null,
"startdate": null,
"enddate": null
}
]
}
Svaret er hentet 06-10-2026 og forkortet. Et selskab i owners kan stå med sit organisationsnummer som name, som revisoren her.
Changed feed - nye/ændrede virksomheder
// Danmark
GET /api/v2/dk/changed/list/company?since=2026-10-05&limit=2
{
"since": "2026-10-05",
"total": 4337,
"limit": 2,
"items": [
{
"vat": 46258886,
"name": "Snacki Solutions",
"companydesc": "ENK",
...
},
...
],
"next_cursor": "1791163019000,44296632"
}
// Pagination: brug next_cursor som cursor parameter
GET /api/v2/dk/changed/list/company?since=2026-10-05&limit=2&cursor=1791163019000,44296632
// Norge
GET /api/v2/no/changed/list/company?since=2026-04-02&limit=100
{
"since": "2026-04-02",
"total": 451,
"limit": 100,
"items": [
{
"orgnr": "922827044",
"updateId": 24075678,
"date": "2026-04-02",
"changeType": "Ny enhet"
}
],
"next_cursor": "24075687"
}
// Parametre: since (YYYY-MM-DD, valgfri, standard er i går),
// limit (standard 100, max 1.000 i DK og 100 i NO), cursor.
// DK-feedet kan også filtreres med industrycode.
// Hvornår en enkelt virksomhed sidst blev opdateret hos os:
GET /api/v2/dk/changed/company/40101772
// {"vat":40101772,"last_changed":"2026-10-06T03:00:41.387067+00:00"}
Kontakt-scraping (asynkron)
POST /api/v2/dk/company/24256790/contacts/scrape
Content-Type: application/json
Authorization: Bearer DIN_API_NØGLE
// Svar (202 Accepted):
{
"job_id": "abc123-def456",
"status": "pending",
"message": "Scrape job oprettet. Poll GET /dk/company/{cvr}/scrape-jobs/{id} for status."
}
Statuskoder
API'et bruger standard HTTP-statuskoder:
| Kode | Betydning | Beskrivelse |
|---|---|---|
200 |
OK | Anmodningen lykkedes |
202 |
Accepted | Asynkront job oprettet (kontakt-scraping) |
304 |
Not Modified | Data er uændret siden din ETag (se Conditional GET) |
400 |
Bad Request | Ugyldigt CVR-nummer eller manglende parametre |
401 |
Unauthorized | Manglende, ugyldig eller udløbet API-nøgle, eller deaktiveret konto |
403 |
Forbidden | Din plan har ikke adgang til dette endpoint (TIER_REQUIRED), eller din IP er blokeret (IP_BLOCKED) |
404 |
Not Found | Virksomheden findes ikke i CVR-registret |
405 |
Method Not Allowed | Forkert HTTP-metode, fx POST på et GET-endpoint (METHOD_NOT_ALLOWED) |
429 |
Too Many Requests | Kvoten er brugt (QUOTA_EXCEEDED), for mange kald på kort tid (RATE_LIMITED), eller grænsen for kald uden nøgle kunne ikke tjekkes (RATE_CHECK_FAILED, prøv igen om et minut) |
500 |
Server Error | Intern serverfejl. Prøv igen senere |
502 |
Bad Gateway | Kilden (CVR-registret eller Brønnøysundregistrene) svarede ikke (UPSTREAM_ERROR eller CVR_API_ERROR) |
503 |
Service Unavailable | Tjenesten er midlertidigt utilgængelig (SERVICE_UNAVAILABLE) |
Hvad tæller i kvoten: 304, 403, 404, 429 og 5xx tæller ikke med. Andre svar tæller med, også 400.
Fejlkoder
| Kode | Status | Hvornår |
|---|---|---|
API_KEY_REQUIRED |
401 | Kald uden nøgle fra et script (fx curl eller python-requests) |
AUTH_ERROR |
401 | Nøglen er forkert eller ikke længere aktiv |
TOKEN_EXPIRED |
401 | Nøglen er udløbet. Lav en ny under API-nøgler i dashboardet |
USER_DISABLED |
401 | Kontoen er deaktiveret |
QUOTA_EXCEEDED |
429 | Dags- eller månedskvoten er brugt |
RATE_LIMITED |
429 | For mange kald på kort tid. Gælder kun gratisplanen, som har en grænse pr. minut og pr. time |
RATE_CHECK_FAILED |
429 | Grænsen for kald uden nøgle kunne ikke tjekkes. Prøv igen om et minut |
INVALID_VAT |
400 | Ugyldigt CVR-nummer på /dk/company/{cvr} |
INVALID_CVR |
400 | Ugyldigt CVR-nummer på regnskabs-endpoints og andre undersider, fx /accounts, /structure og /capital-changes |
INVALID_ORGNR |
400 | Ugyldigt norsk organisationsnummer på /no/company/{orgnr} (skal være 9 cifre) |
INVALID_PARAMETER |
400 | En parameter har en ugyldig værdi, fx limit der ikke er et positivt heltal, eller since der ikke er en dato |
INVALID_QUERY |
400 | Søgning uden et gyldigt søgekriterium |
TIER_REQUIRED |
403 | Din plan har ikke adgang til endpointet |
IP_BLOCKED |
403 | Kald uden nøgle fra din IP-adresse er blokeret, permanent eller midlertidigt efter for mange kald |
NETWORK_BLOCKED |
403 | Kald uden nøgle fra hele dit IP-netværk er blokeret efter gentaget misbrug fra flere adresser |
NOT_FOUND |
404 | Virksomheden eller data findes ikke |
INTERNAL_ERROR |
500 | Fejl hos os, fx når godkendelsen af nøglen fejler. Prøv igen om lidt |
Fejl-response format
Alle 4xx og 5xx svar returnerer JSON med konsistent struktur. Kald uden nøgle fra et script (fx curl):
HTTP/2 401
{
"error": "API_KEY_REQUIRED",
"message": "API-nøgle påkrævet. Send den som header: 'X-API-Key: din-nøgle'. Hent gratis nøgle på datacvrapi.dk/opret-konto (25 opslag/dag). Se docs: datacvrapi.dk/cvr-api-dokumentation"
}
Kald med en forkert nøgle (samme svar med X-API-Key og Authorization: Bearer):
HTTP/2 401
{
"error": "AUTH_ERROR",
"message": "Ugyldig eller manglende API-nøgle. Se datacvrapi.dk/cvr-api-dokumentation"
}
Ugyldigt CVR-nummer på /dk/company/1234:
HTTP/2 400
{
"error": "INVALID_VAT",
"message": "Ugyldigt CVR-nummer. Et dansk CVR-nummer består af 8 cifre og kan ikke starte med 0"
}
Regnskabs-endpoints bruger en anden kode, fx /dk/company/1234/accounts:
HTTP/2 400
{
"error": "INVALID_CVR",
"message": "CVR-nummer skal være præcis 8 cifre"
}
Opbrugt månedskvote på en betalt plan, her Hobby:
HTTP/2 429
Retry-After: (sekunder til månedsskiftet)
{
"error": "QUOTA_EXCEEDED",
"message": "Månedskvoten er brugt (10.000 opslag). Kvoten nulstilles den 1. i måneden. Skal du bruge mere nu, kan du skifte plan under Abonnement i dashboardet: datacvrapi.dk/dashboard/abonnement"
}
Rate limiting
Kvoten afhænger af din plan. Priserne er de samme som på prissiden:
| Plan | Opslag | Pris |
|---|---|---|
| Gratis | 25 / dag | 0 kr. |
| Start | 1.500 / md | 99 kr./md. ekskl. moms |
| Hobby | 10.000 / md | 299 kr./md. ekskl. moms |
| Business | 50.000 / md | 499 kr./md. ekskl. moms |
| Business+ | 100.000 / md | 699 kr./md. ekskl. moms |
| Custom | Ubegrænset | Kontakt os |
Gratisplanens 25 opslag nulstilles ved midnat UTC, og betalte planers månedskvote ved månedsskiftet. Kald uden nøgle fra en browser har 25 opslag om dagen pr. IP-adresse. Gratisplanen har desuden en grænse pr. minut og pr. time; betalte planer har kun månedskvoten.
Når kvoten er brugt, eller du laver for mange kald på kort tid, returnerer API'et statuskode 429 med headeren Retry-After. Vent det antal sekunder, før du prøver igen. Er månedskvoten brugt, kan der gå dage til nulstillingen, så det nytter ikke at prøve igen efter få sekunder.
Rate limit headers
Svar på kald med en nøgle på en plan med kvote har disse headers. Planer uden kvote får dem ikke, og kald uden nøgle får dem kun på 429-svaret, når dagens 25 opslag er brugt. X-RateLimit-Remaining er et øjebliksbillede og kan stå stille over flere kald:
| Header | Beskrivelse |
|---|---|
X-RateLimit-Limit |
Maksimalt antal opslag i din nuværende periode (dag eller måned) |
X-RateLimit-Remaining |
Antal opslag du har tilbage |
X-RateLimit-Reset |
Antal sekunder til din kvote nulstilles |
Retry-After |
Sendes kun ved 429. Er kvoten brugt, med eller uden nøgle, er værdien antal sekunder til den nulstilles (dagskvoten ved midnat UTC, månedskvoten ved månedsskiftet). Ved CAPITAL_QUOTA_EXCEEDED er den sekunder til næste ledige opslag. Ellers er den 60 |
Conditional GET (ETag / If-None-Match)
API'et understøtter HTTP Conditional GET på virksomhedsendpoints. Hvis data ikke er ændret siden dit seneste opslag, returnerer API'et 304 Not Modified med tom body, og kaldet tæller ikke mod din månedlige kvote.
Understøttede endpoints:
GET /api/v2/dk/company/{cvr}GET /api/v2/no/company/{orgnr}
Sådan bruger du det
1. Gem ETag-headeren fra dit første svar:
# Trin 1: hent ETag (erstat CVR_NUMMER med et rigtigt CVR-nummer)
curl -s -D - -o /dev/null "https://datacvrapi.dk/api/v2/dk/company/CVR_NUMMER" \
-H "X-API-Key: DIN_API_NØGLE" | grep -i "^etag:"
# etag: "dk-CVR_NUMMER-TIDSSTEMPEL"
# Ingen linje betyder ingen ETag for denne virksomhed lige nu (se Bemærk nedenfor)
# Trin 2: send ETag'en tilbage i If-None-Match med næste kald
curl -s -D - -o /dev/null "https://datacvrapi.dk/api/v2/dk/company/CVR_NUMMER" \
-H "X-API-Key: DIN_API_NØGLE" \
-H 'If-None-Match: "dk-CVR_NUMMER-TIDSSTEMPEL"'
# HTTP/2 304, hvis data er uændret (0 bytes body, tæller ikke mod kvote)
# HTTP/2 200 med de aktuelle data, hvis ETag'en ikke længere passer
Response-headers
| Header | Beskrivelse |
|---|---|
ETag |
Unik version-streng for virksomhedens data. Format: "country-cvr-timestamp" |
Last-Modified |
Hvornår virksomhedens data sidst blev ændret (RFC 7231 datoformat) |
Vary |
Altid X-API-Key, Authorization på ETag-responses |
Kvote-besparelse
Et kald der returnerer 304 Not Modified registreres i din log, men tæller ikke mod din månedlige kvote. Det sparer mest, når du slår de samme virksomheder op igen inden for få dage.
Bemærk: ETag og Last-Modified sendes kun, når vores kopi af virksomheden er opdateret inden for de seneste 7 dage, eller virksomheden er ophørt. Er kopien ældre, henter API'et data fra CVR-registret, og svaret er et 200 uden ETag. Den 06-10-2026 gav fx 24256790 og 22756214 svar uden ETag. Send kun If-None-Match, når du har fået en ETag.
Kodeeksempler
cURL
curl -X GET "https://datacvrapi.dk/api/v2/dk/company/24256790" \
-H "Authorization: Bearer DIN_API_NØGLE"
JavaScript (fetch)
const response = await fetch(
'https://datacvrapi.dk/api/v2/dk/company/24256790',
{
headers: {
'Authorization': 'Bearer DIN_API_NØGLE'
}
}
);
if (!response.ok) {
throw new Error(`API fejl: ${response.status}`);
}
const virksomhed = await response.json();
console.log(virksomhed.name); // "NOVO NORDISK A/S"
console.log(virksomhed.companystatus); // "Aktiv"
Python (requests)
import requests
url = "https://datacvrapi.dk/api/v2/dk/company/24256790"
headers = {
"Authorization": "Bearer DIN_API_NØGLE"
}
response = requests.get(url, headers=headers)
response.raise_for_status()
virksomhed = response.json()
print(virksomhed["name"]) # "NOVO NORDISK A/S"
print(virksomhed["companystatus"]) # "Aktiv"
Hent regnskabsdata (JavaScript)
// Hent seneste årsregnskab for en virksomhed
async function hentSenesteRegnskab(cvr, apiKey) {
const response = await fetch(
`https://datacvrapi.dk/api/v2/dk/company/${cvr}/accounts/latest`,
{
headers: { 'Authorization': `Bearer ${apiKey}` }
}
);
if (response.status === 403) {
console.error('Business-abonnement påkrævet for regnskabsdata');
return null;
}
return response.json();
}
// /accounts/latest giver ét regnskabsobjekt (seneste helår).
// /accounts giver { cvr, count, accounts: [...] } og kan også indeholde
// kvartals- og halvårsrapporter, så accounts[0] er ikke altid årsregnskabet.
const seneste = await hentSenesteRegnskab('24256790', 'DIN_API_NØGLE');
if (seneste) {
console.log('Periode:', seneste.period_start, 'til', seneste.period_end); // 2025-01-01 til 2025-12-31
console.log('Omsætning:', seneste.figures.revenue); // 309064000000
console.log('Egenkapital:', seneste.figures.equity);
}
SDKs og integrationer
DataCVR API er en standard REST API og kan bruges med enhver HTTP-klient. Vi tilbyder desuden:
- Postman Collection: Importér vores endpoints direkte i Postman for hurtig test
- cURL-eksempler: Kopiér og tilpas til dit system
- Integration guides: Se vores trin-for-trin integration guide med eksempler i JavaScript, Python, PHP og C#
Vi arbejder på officielle SDKs til JavaScript/TypeScript og Python. Følg med på vores dashboard for opdateringer.
Næste skridt
Nu har du overblikket over DataCVR API. Her er, hvad du kan gøre nu:
- Opret en gratis konto og få din API-nøgle
- Læs vores integration guide med kodeeksempler i flere sprog
- Se API changelog for versionshistorik og seneste ændringer
- Udforsk hvilke virksomhedsdata der er tilgængelige
- Se priser og planer for at vælge den rette løsning