# Cleanse addresses in Make with the HTTP module

> Set up the HTTP module in a Make scenario against datavask, map the fields correctly, and handle 429 and errors with a router or an error handler.
>
> https://danadresse.dk/en/guides/make · verified 2026-11-02
Make does not need a dedicated Danadresse app. The built-in **HTTP** module calls the API directly, and with *Parse response* turned on the response becomes fields you can map onward. The short recipe is at [/en/integrationer/make](/en/integrationer/make). This guide goes further: exact field mapping, the key in a header, and what to do about errors and 429.

## 1. Set up the HTTP module

Add **HTTP → Make a request** after the module that delivers the address (Google Sheets, a webhook, your CRM). Fill in:

| Field | Value |
|---|---|
| URL | `https://api.danadresse.dk/datavask/adgangsadresser` |
| Method | `GET` |
| Headers | Name `X-Api-Key`, Value your key |
| Query String | Name `betegnelse`, Value the address from the previous module, e.g. `{{1.Adresse}}` |
| Parse response | Yes |

Send the key as a header rather than as `api_key` in the query string. The query string appears in the scenario's execution log together with the URL, so anyone with access to the log can see the key. If your HTTP module has a field for API-key authentication, you can store the key there with the header name `X-Api-Key`.

`/datavask/adgangsadresser` matches the entrance (street, house number, postcode). To hit a specific flat, use `/datavask/adresser`: it reads floor and door straight from `betegnelse` (`Strandvejen 100, 2. tv, 2900 Hellerup`), and `adresse` then also has `etage`, `dør` and `adgangsadresseid`. If you have the parts in separate fields, you can send `vejnavn`, `husnr`, `etage`, `dør` and `postnr` as separate query parameters instead.

## 2. Map the fields

With *Parse response* the response sits under `data`. `resultater` is a list with the best match first, and Make counts from 1. Assuming the HTTP module is module number 2:

| You need | Mapping |
|---|---|
| Category (A, B or C) | `{{2.data.kategori}}` |
| Access address id | `{{2.data.resultater[1].adresse.id}}` |
| Street name | `{{2.data.resultater[1].adresse.vejnavn}}` |
| House number | `{{2.data.resultater[1].adresse.husnr}}` |
| Postcode | `{{2.data.resultater[1].adresse.postnr}}` |
| City | `{{2.data.resultater[1].adresse.postnrnavn}}` |
| HTTP status | `{{2.statusCode}}` |

The response the mapping is based on looks like this:

```json id=response-shape run=no
{
  "kategori": "A",
  "resultater": [
    {
      "adresse": {
        "id": "0a3f507c-0624-32b8-e044-0003ba298018",
        "vejnavn": "Strandvejen",
        "adresseringsvejnavn": "Strandvejen",
        "husnr": "100",
        "supplerendebynavn": null,
        "postnr": "2900",
        "postnrnavn": "Hellerup",
        "status": 1,
        "href": "…"
      },
      "aktueladresse": { "…": "same fields, the current version" },
      "vaskeresultat": {
        "afstand": 0,
        "forskelle": { "vejnavn": 0, "husnr": 0, "postnr": 0, "postnrnavn": 0 },
        "ukendtetokens": []
      }
    }
  ]
}
```

If `resultater` is empty, the category is C and every `resultater[1]` field is empty. Check for that in a filter before writing back.

The cleanse answer has no municipality or coordinates. If you need them, add a second HTTP module with the URL `https://api.danadresse.dk/adgangsadresser/{{2.data.resultater[1].adresse.id}}` and the same header. Map `kommune.kode`, `kommune.navn` and `adgangspunkt.koordinater[1]` / `[2]` (longitude, latitude) from its `data`. That is one extra call per row.

## 3. Split the flow with a router

Put a **Router** after the HTTP module with three routes:

1. Filter: `{{2.statusCode}}` = 200 and `{{2.data.kategori}}` is A or B → write the address back. A is an exact match. B is one safe match with small spelling differences, so write back the official text from the result, not the input.
2. Filter: `{{2.statusCode}}` = 200 and `{{2.data.kategori}}` = C → send to manual review (Slack, email, a tab in your sheet). C means several candidates or larger differences; never accept it automatically.
3. The fallback route: everything else → log the status and the address so you can rerun them.

The router only works if the HTTP module does not stop the scenario on errors. So set **Evaluate all states as errors** to *No* in the module's advanced settings. 4xx and 5xx responses then continue as ordinary bundles with a `statusCode`.

## 4. 429 and retries

There are two kinds of 429, and they need different handling:

| Code | Header | What to do |
|---|---|---|
| `rate_limit_per_minute` | `Retry-After` (1-60 seconds) | Too many calls in a minute. Wait and retry |
| `quota_exceeded` | no `Retry-After` | The free plan's monthly quota and its 20 % grace are used up. Stop until the 1st of next month, or upgrade |

The code is in `{{2.data.code}}`, because error responses on the DAWA paths have the shape `{"type", "title", "details", "code"}`. For `quota_exceeded`, `{{2.data.title}}` is a plain-language explanation, `{{2.data.details.resets_at}}` says when the quota resets, and `{{2.data.details.upgrade_url}}` links to the upgrade page. Refused calls are not counted.

If you would rather let Make retry automatically, leave *Evaluate all states as errors* on *Yes*, right-click the HTTP module and choose **Add error handler → Break**. Set the number of attempts to 3 and the interval to 1 minute. That requires *Allow storing of incomplete executions* to be on in the scenario settings. Break helps with the per-minute limit, not with a used-up monthly quota.

If the scenario processes many rows at once, add **Tools → Sleep** for 1 second after the HTTP module. On the free plan the limit is 360 calls per minute.

## Test the call

The same call the HTTP module makes, from a terminal:

```bash id=test-call run=live expect="kategori"
curl -s "https://api.danadresse.dk/datavask/adgangsadresser?betegnelse=Strandvejen%20100%2C%202900%20Hellerup" \
  -H "X-Api-Key: $DANADRESSE_API_KEY"
```

## Next steps

- [Zapier](/en/guides/zapier) and [n8n](/en/guides/n8n) — the same setup in other tools.
- [Limits, quotas and 429](/en/guides/graenser-og-429)
- Short recipe: [/en/integrationer/make](/en/integrationer/make)
