Jobs via API
Alt, hvad du kan i dashboardets Jobs, kan du også fra din egen kode. Base-URL'en er https://api.danskadresseapi.dk.
Nøgle: Send en live-nøgle med scope batch som Authorization: Bearer <nøgle>. En pub-nøgle kan ikke bruges, og planen skal være Pro eller Enterprise.
Endpoints
| Kald | Gør |
|---|---|
POST /v1/jobs | Opretter et job. Svarer 202 med jobbet og en Location-header |
GET /v1/jobs | Teamets jobs, nyeste først (?limit= op til 100, ?foer=<tidspunkt> for næste side) |
GET /v1/jobs/{id} | Status, fremdrift, rækker pr. sekund, forventet tid (eta_sek), job_fejl og raekke_fejl |
GET /v1/jobs/{id}/resultat | Resultatet — ?format=ndjson (standard) eller ?format=csv |
GET /v1/jobs/{id}/fejl | Rækkerne, der ikke gav et (sikkert) svar — ?format=csv (standard) eller ndjson, evt. ?aarsag= og ?sprog=en |
POST /v1/jobs/{id}/pause | Sætter et job i kø eller i gang på pause — den del, der er i gang, gøres færdig og gemmes |
POST /v1/jobs/{id}/genoptag | Genoptager et job på pause, hvor det slap. Svarer 202 (evt. med advarsel om kvoten) |
DELETE /v1/jobs/{id} | Annullerer et job i kø, i gang eller på pause |
Kvote: Kun jobbets rækker tæller — hver række, der gav et svar, som ét opslag. Rækker, der fejler, og selve POST-kaldet koster ikke noget. Status, resultat, fejlrækker, pause og annullering tæller ikke i kvoten, men følger planens rate limit.
Opret et job
Der er tre måder at sende filen på:
1. Rå fil — sæt Content-Type efter formatet, og angiv type (og evt. variant og navn) i URL'en:
| Format | Content-Type |
|---|---|
| CSV | text/csv |
| TSV | text/tab-separated-values |
| NDJSON | application/x-ndjson |
2. JSON med elementerne — {"type": …, "variant": …, "navn": …, "input": [ … ]} med Content-Type: application/json.
3. JSON med rå data — {"type": …, "format": "csv", "data": "<filens indhold>"}.
variant er adresser eller adgangsadresser for datavask og bygninger eller enheder for BBR. Udelader du den, bruges den første. Filens format er beskrevet i Filformat til jobs.
Svaret er jobbet med status koe. Rækker kvoten ikke til hele jobbet, står der en advarsel i svaret — jobbet stopper så med kvote_stop, når kvoten er brugt. Afvises oprettelsen, står årsagen i error.details.kode — se Når et job fejler — fejlkoder.
Statussvaret
{
"id": "7c0e6f0a-3b1d-4f5e-9a51-2d4c8b1e9f20",
"type": "datavask",
"variant": "adresser",
"kilde": "api",
"navn": "kunder-oktober",
"status": "koerer",
"total": 48522,
"behandlet": 21000,
"fejl": 140,
"procent": 43.3,
"raekker_pr_sek": 1840,
"eta_sek": 15,
"afregnede_opslag": 20860,
"fejlbesked": null,
"oprettet": "2026-10-04T14:11:31.000Z",
"startet": "2026-10-04T14:11:32.000Z",
"faerdig": null,
"udloeber": null,
"resultat": null,
"job_fejl": null,
"venter_paa_kapacitet": false,
"venter_kapacitet_siden": null,
"pauset": null,
"raekke_fejl": {
"total": 140,
"pr_aarsag": { "ikke_tolket": 140 },
"advarsler": { "total": 512, "pr_aarsag": { "flere_mulige": 380, "intet_match": 132 } },
"daekket_raekker": 21000
}
}status— se betydningen i Følg et job og hent resultatet.fejl— antal rækker uden svar.raekke_fejlfordeler dem (og advarslerne) pr. årsag.job_fejl— ernull, medmindre jobbet er stoppet af en fejl. Så står koden ijob_fejl.kode, og en evt. reference til support ijob_fejl.reference.venter_paa_kapacitet—true, mens et kørende job venter med sin næste del, fordi API'et er travlt (almindelige kald går forud; Enterprise-jobs venter først ved højere belastning end Pro-jobs). Jobbet venter højst ca. 2 minutter pr. del, intet går tabt, ogventer_kapacitet_sidenfortæller, hvornår ventetiden begyndte.pauset— hvornår jobbet blev sat på pause (kun ved statuspauset).resultat— links til resultatet, når der er noget at hente.
Hent resultatet
GET /v1/jobs/{id}/resultat virker, når status er faerdig — og giver delresultatet, når status er pauset, fejlet, kvote_stop eller annulleret. Resultatet strømmes del for del, så også store resultater kan hentes.
409— jobbet er ikke færdigt endnu.410— resultatet er udløbet og slettet.
Headerne X-Job-Status og X-Job-Raekker fortæller, hvilken status og hvor mange rækker du fik.
Eksempler
cURL — opret et datavask-job fra en CSV-fil, følg det og hent resultatet:
# Opret jobbet
curl -X POST "https://api.danskadresseapi.dk/v1/jobs?type=datavask&variant=adresser&navn=kunder" \
-H "Authorization: Bearer $ADDR_KEY" \
-H "Content-Type: text/csv" \
--data-binary @adresser.csv
# Følg status (brug id'et fra svaret)
curl "https://api.danskadresseapi.dk/v1/jobs/JOB_ID" \
-H "Authorization: Bearer $ADDR_KEY"
# Hent resultatet som CSV
curl -o resultat.csv "https://api.danskadresseapi.dk/v1/jobs/JOB_ID/resultat?format=csv" \
-H "Authorization: Bearer $ADDR_KEY"
# Hent fejlrækkerne
curl -o fejl.csv "https://api.danskadresseapi.dk/v1/jobs/JOB_ID/fejl" \
-H "Authorization: Bearer $ADDR_KEY"Python
import os, time, requests
API = "https://api.danskadresseapi.dk"
H = {"Authorization": "Bearer " + os.environ["ADDR_KEY"]}
with open("koordinater.csv", "rb") as f:
r = requests.post(API + "/v1/jobs", params={"type": "reverse"},
headers={**H, "Content-Type": "text/csv"}, data=f)
r.raise_for_status()
job = r.json()
while job["status"] in ("koe", "koerer"):
time.sleep(3)
job = requests.get(API + "/v1/jobs/" + job["id"], headers=H).json()
if job["job_fejl"]:
print("Fejlkode:", job["job_fejl"]["kode"], job["job_fejl"]["besked"])
if job["resultat"]:
res = requests.get(API + "/v1/jobs/" + job["id"] + "/resultat",
params={"format": "csv"}, headers=H)
open("resultat.csv", "wb").write(res.content)JavaScript (Node 18+)
const API = "https://api.danskadresseapi.dk";
const H = { Authorization: "Bearer " + process.env.ADDR_KEY };
const opret = await fetch(API + "/v1/jobs", {
method: "POST",
headers: { ...H, "Content-Type": "application/json" },
body: JSON.stringify({
type: "bbr",
variant: "bygninger",
input: ["57a791c4-25b0-4e57-8143-aa5b08efec51", "6c16b07d-acb1-414e-9d24-443340fe382e"],
}),
});
let job = await opret.json();
if (!opret.ok) throw new Error(job.error.message + " (" + job.error.details?.kode + ")");
while (job.status === "koe" || job.status === "koerer") {
await new Promise((r) => setTimeout(r, 3000));
job = await (await fetch(API + "/v1/jobs/" + job.id, { headers: H })).json();
}
const ndjson = await (await fetch(API + "/v1/jobs/" + job.id + "/resultat", { headers: H })).text();
const raekker = ndjson.trim().split("\n").map((l) => JSON.parse(l));I stedet for at spørge efter status igen og igen kan du abonnere på webhooken job.completed (og job.failed) og hente resultatet, når den kommer. Se Notifikationer og webhooks for jobs.
Annullér et job
curl -X DELETE "https://api.danskadresseapi.dk/v1/jobs/JOB_ID" \
-H "Authorization: Bearer $ADDR_KEY"Jobbet får status annulleret, og det, der nåede at blive behandlet, kan hentes. Er jobbet allerede afsluttet, svarer API'et 409.
Pause og genoptag
curl -X POST "https://api.danskadresseapi.dk/v1/jobs/JOB_ID/pause" \
-H "Authorization: Bearer $ADDR_KEY"
curl -X POST "https://api.danskadresseapi.dk/v1/jobs/JOB_ID/genoptag" \
-H "Authorization: Bearer $ADDR_KEY"pause virker for et job i kø eller i gang: den del, der er i gang, gøres færdig og gemmes, og jobbet får status pauset. genoptag virker kun for et job på pause (ellers 409) — kvoten tjekkes først, og jobbet fortsætter præcis efter sidste gemte række. Et fejlet, kvote_stop eller annulleret job fortsættes med Fortsæt i dashboardet.
Synkrone batch-kald og kvoten
De synkrone batch-endpoints (fx POST /v1/datavask/adresser/batch) tjekker kvoten for hele batchen, før noget behandles. Er der ikke plads til alle elementerne, svarer API'et 429 — intet er behandlet, og intet er afregnet:
{
"error": {
"type": "quota_exceeded",
"message": "Batchen har 500 elementer, men der er kun 120 opslag tilbage af kvoten i denne periode. Intet er behandlet eller afregnet. …",
"code": 429,
"details": { "antal": 500, "tilbage": 120, "grund": "kvote", "upgrade_url": "https://danskadresseapi.dk/dashboard/fakturering" }
}
}details.antal— antal elementer, du sendte.details.tilbage— hvor mange opslag der er plads til. Send en mindre batch (højsttilbageelementer), opgradér, eller vent til kvoten nulstilles.- Samtidige batch-kald på samme team reserverer hver sin plads, så de tilsammen aldrig går over kvoten. Det kald, der ikke får plads, får
429meddetails.reserveret_samtidig(opslag, som de andre kald har reserveret). details.retry_after_secondsog headerenRetry-Afterer kun med, når kvoten nulstilles inden for en time.
rate_limit_exceeded eller quota_exceeded? Ved rate_limit_exceeded sender du for hurtigt — vent og send samme kald igen uændret. Ved quota_exceeded hjælper det ikke at sende samme kald igen, før kvoten nulstilles — send en mindre batch, eller opgradér.
Et job opfører sig anderledes: det kører, til kvoten er brugt, stopper med status kvote_stop, og delresultatet kan hentes. Derfor er et job ofte det bedste valg til store mængder.
Mere
- API-referencen: danskadresseapi.dk/docs
- Guiden om batch og jobs: danskadresseapi.dk/guides/batch-api
