Valider adressen i checkout med datavask
Tjek kundens adresse, når formularen sendes, accepter sikre match, bekræft sandsynlige og bed om rettelse ved usikre.
En forkert leveringsadresse koster en returpakke, en ekstra fragt og en irriteret kunde. Autocomplete fanger de fleste fejl, mens kunden skriver, men ikke alle: nogle indsætter adressen fra et andet sted, nogle har slået JavaScript fra, og nogle ordrer kommer ind via API. Datavask på serveren er sikkerhedsnettet, der kører, når formularen sendes.
Endpointet er GET /datavask/adresser (med etage og dør) eller GET /datavask/adgangsadresser (kun bygningens indgang). Svaret har samme form som DAWA's datavask. Feltet kategori øverst i svaret er A for et præcist match, B for ét sikkert match med små stavefejl og C for usikkert.
1. Send adressen
Det enkleste er hele adressen som én tekst i betegnelse:
curl -s -G "https://api.danadresse.dk/datavask/adresser" \ --data-urlencode "betegnelse=Strandvejen 100, 1., 2900 Hellerup" \ -H "X-Api-Key: $DANADRESSE_API_KEY"
Parseren læser etage og dør (2. tv, st. th, 1.mf), husbogstaver med små bogstaver (12a), et postnummer hvor som helst i teksten og aa/å-stavemåder (Aabenraa, Kobenhavn). Store bogstaver og et afsluttende punktum (1., TV) gør ingen forskel.
Har din formular separate felter, kan du sende dem i stedet: vejnavn, husnr, etage, dør, postnr og supplerendebynavn. Resultatet er det samme.
POST virker også: POST /datavask/adresser med én adresse som JSON-body, enten {"betegnelse": "…"} eller de separate felter. Hvert kald vasker én adresse. Skal du vaske mange adresser, så se Rens en CSV-fil fra CRM'et.
2. Læs svaret
Kunden skrev "Strandvej" i stedet for "Strandvejen". Vasken finder præcis én adresse og svarer B:
{
"kategori": "B",
"resultater": [
{
"adresse": {
"id": "0a3f50a4-0c39-32b8-e044-0003ba298018",
"vejnavn": "Strandvejen",
"adresseringsvejnavn": "Strandvejen",
"husnr": "100",
"supplerendebynavn": null,
"postnr": "2900",
"postnrnavn": "Hellerup",
"status": 1,
"virkningstart": "2000-02-05T19:44:20.000Z",
"virkningslut": null,
"adgangsadresseid": "0a3f507c-0624-32b8-e044-0003ba298018",
"etage": "1",
"dør": null,
"href": "https://api.danadresse.dk/adresser/0a3f50a4-0c39-32b8-e044-0003ba298018"
},
"aktueladresse": {
"id": "0a3f50a4-0c39-32b8-e044-0003ba298018",
"...": "samme felter som adresse"
},
"vaskeresultat": {
"variant": {
"vejnavn": "Strandvejen",
"husnr": "100",
"etage": "1",
"dør": null,
"supplerendebynavn": null,
"postnr": "2900",
"postnrnavn": "Hellerup"
},
"afstand": 2,
"forskelle": {
"vejnavn": 2,
"husnr": 0,
"postnr": 0,
"postnrnavn": 0,
"etage": 0
},
"parsetadresse": {
"vejnavn": "Strandvej",
"husnr": "100",
"etage": "1",
"postnr": "2900",
"postnrnavn": "Hellerup"
},
"ukendtetokens": [],
"anvendtstormodtagerpostnummer": null
}
}
]
}| Felt | Brug |
|---|---|
kategori | A, B eller C for hele vasken. Det er den eneste kategori i svaret |
resultater | Kandidaterne, bedste først. Ved A og B er der præcis én |
adresse.id | Adressens UUID. Gem den på ordren |
adresse.adgangsadresseid | Bygningens indgang. Gem den også |
adresse.vejnavn m.fl. | Den officielle stavemåde. Brug den i stedet for kundens |
aktueladresse | Den gældende version af adressen. Afviger fra adresse, hvis matchet er en nedlagt adresse |
vaskeresultat.afstand | Redigeringsafstand mellem input og adressen. 0 er præcist |
vaskeresultat.forskelle | Afstanden pr. felt, f.eks. vejnavn: 2. Viser, hvad kunden skrev forkert |
vaskeresultat.ukendtetokens | Ord i input, der ikke matchede noget, f.eks. ["tv"], når adressen ikke har døren "tv" |
Svaret har ikke et samlet tekstfelt. Byg linjen selv af felterne, eller hent adressebetegnelse med GET /adresser/{id}.
3. Beslut: accepter, bekræft eller spørg
Brug kategori øverst i svaret:
| kategori | Handling |
|---|---|
| A | Accepter. Gem id og adgangsadresseid |
| B | Accepter, men gem den officielle tekst. Du kan vise den: "Vi leverer til Strandvejen 100, 1., 2900 Hellerup" |
| C | Vis kandidaterne fra resultater, og lad kunden vælge eller rette adressen. Vælg aldrig en automatisk |
tom resultater | Bed kunden tjekke adressen. Bloker ikke nødvendigvis ordren |
Etage og dør tæller med i kategorien. Skriver kunden en etage eller dør, der ikke findes på adressen, svarer vasken C med de enheder, der findes, som kandidater.
I Python:
import os import requests def vask(betegnelse): r = requests.get( "https://api.danadresse.dk/datavask/adresser", params={"betegnelse": betegnelse}, headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]}, timeout=5, ) r.raise_for_status() svar = r.json() resultater = svar["resultater"] if not resultater: return "ask", [] if svar["kategori"] == "A": return "accept", resultater[:1] if svar["kategori"] == "B": return "confirm", resultater[:1] return "choose", resultater[:5] # C: lad kunden vælge beslutning, kandidater = vask("Strandvej 100, 1., 2900 Hellerup") print(f"beslutning={beslutning}") for k in kandidater: a = k["adresse"] print(a["id"], a["vejnavn"], a["husnr"], a["etage"], a["postnr"], k["vaskeresultat"]["forskelle"])
Samme logik i Node 18+:
async function vask(betegnelse) { const url = new URL("https://api.danadresse.dk/datavask/adresser"); url.searchParams.set("betegnelse", betegnelse); const res = await fetch(url, { headers: { "X-Api-Key": process.env.DANADRESSE_API_KEY }, signal: AbortSignal.timeout(5000), }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const { kategori, resultater } = await res.json(); if (resultater.length === 0) return { beslutning: "ask", kandidater: [] }; if (kategori === "A") return { beslutning: "accept", kandidater: resultater.slice(0, 1) }; if (kategori === "B") return { beslutning: "confirm", kandidater: resultater.slice(0, 1) }; return { beslutning: "choose", kandidater: resultater.slice(0, 5) }; } // Rentemestervej 8 har ingen "2. tv": vasken svarer C med de enheder, der findes const { beslutning, kandidater } = await vask( "Rentemestervej 8, 2. tv, 2400 København NV", ); console.log(`beslutning=${beslutning}`); for (const { adresse: a } of kandidater) { console.log( `${a.vejnavn} ${a.husnr}, ${a.etage ?? "-"}. ${a["dør"] ?? ""}, ${a.postnr} ${a.postnrnavn}`, ); }
Og i PHP med curl-udvidelsen:
<?php function vask(string $betegnelse): array { $ch = curl_init('https://api.danadresse.dk/datavask/adresser?' . http_build_query(['betegnelse' => $betegnelse])); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 5, CURLOPT_HTTPHEADER => ['X-Api-Key: ' . getenv('DANADRESSE_API_KEY')], ]); $svar = json_decode(curl_exec($ch), true); curl_close($ch); $res = $svar['resultater'] ?? []; if (!$res) return ['ask', []]; if ($svar['kategori'] === 'A') return ['accept', array_slice($res, 0, 1)]; if ($svar['kategori'] === 'B') return ['confirm', array_slice($res, 0, 1)]; return ['choose', array_slice($res, 0, 5)]; } [$beslutning, $kandidater] = vask('Raadhuspladsen 1, 1550 København V'); echo "beslutning=$beslutning\n"; foreach ($kandidater as $k) echo $k['adresse']['id'] . ' ' . $k['adresse']['vejnavn'] . "\n";
4. Gem id'erne på ordren
Når adressen er accepteret eller bekræftet, gemmer du adresse.id og adresse.adgangsadresseid sammen med teksten. Id'erne er stabile UUID'er fra Danmarks Adresseregister, så du senere kan slå adressen op igen eller berige den. Se Gem adresse-id'et.
Kanttilfælde
- Stavemåde. "Strandvej" og "Raadhuspladsen" giver B med det officielle navn, fordi der er præcis ét sikkert match. Gem den officielle stavemåde, ikke kundens.
- Forkert postnummer. Et postnummer, der ikke passer til vejen, tæller som en forskel (
forskelle.postnr) og giver C. Vis kunden kandidaterne, og lad dem rette. - Forkert husnummer. Et nummer, der ikke findes på vejen, giver C med nærliggende numre som kandidater.
- Etage og dør udeladt. Uden etage og dør matcher vasken adressen på indgangsniveau, hvis registret har en. Spørg efter etage og dør i formularen, når du leverer til lejligheder.
- Nye adresser. En adresse, der lige er oprettet, kan mangle et kort stykke tid. Lad kunden fortsætte med en markering på ordren, så I kan tjekke den manuelt.
- Timeout eller fejl. Sæt en kort timeout (3-5 sekunder) og lad ordren gå igennem, hvis API'et ikke svarer. Valider den bagefter. En tabt ordre koster mere end en adresse, der skal rettes.
- Nøgle. Kald datavask fra din server med en almindelig nøgle. En browsernøgle virker også på
/datavask/adresser, men så kan kunden springe tjekket over.
Næste skridt
- Hjælp kunden, før de sender: Autocomplete-widget i ren JavaScript eller siden om adresse i checkout.
- Gem adresse-id'et og valider igen senere
- Rens en CSV-fil fra CRM'et
Relaterede guides
Markdown-kilde Fejl i guiden? Skriv til os API-reference (Swagger)