Error 403: access denied
Work out why a valid key is refused from the code in the 403 response, and fix the domains, key type, IP list or a blocked key.
Status 403 means the API knows your key but will not run this particular call with it. There are several reasons, and the code in the response tells you which. Find the code and go straight to the matching section.
code | In short |
|---|---|
origin_not_allowed | Browser key used from a domain not on its list, or from a server |
browser_key_scope | Browser key used on an endpoint it may not call |
sandbox_scope | Test key used on an endpoint it may not call |
key_blocked | The key is blocked because it looks leaked |
ip_not_allowed | IP-locked key used from another IP address |
account_suspended | The account is suspended |
forbidden | Your IP is blocked by the abuse filter |
On the DAWA paths the code is in code and type is ForbiddenError. On /api/v1 it is in error.code. See The error format.
This script shows the status, code and message for a call with your key, and whether the key is flagged as possibly leaked:
import os import requests r = requests.get( "https://api.danadresse.dk/postnumre/8000", headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]}, timeout=10, ) try: body = r.json() except ValueError: body = {} err = body.get("error") if isinstance(body.get("error"), dict) else body print(r.status_code, err.get("code") or "OK", err.get("title") or err.get("message") or "") status = r.headers.get("X-Danadresse-Key-Status") if status: print("Key status:", status)
origin_not_allowed
{
"type": "ForbiddenError",
"title": "This API key is locked to shop.firma.dk, *.firma.dk and this request came from firma.dk. Add the domain under API-nøgler → Tilladte domæner, or use a server-side key.",
"details": null,
"code": "origin_not_allowed"
}The key has Allowed domains, and the host in the call's Origin header (or Referer when Origin is missing) is not on the list. The message shows both the list and the host that was seen.
The call comes from your server.
- Cause: A server sends neither
OriginnorReferer, so the message sayscame from no Origin/Referer. A domain-locked key only works from a browser. - Fix: Create a separate key without domains for the server.
The domain is missing a variant.
- Cause: The list has
www.firma.dk, but the site runs onfirma.dk, or the other way round.*.firma.dkonly covers subdomains, notfirma.dkitself. - Fix: Add both, for example
firma.dkand*.firma.dk. The port does not matter, only the host name counts.
Development on your own machine.
- Cause:
localhostis not allowed by itself. - Fix: Add
localhostto the list, or use a test key for development.
The page sends no Origin or Referer.
- Cause: Pages opened as
file://, sandboxed iframes (Originnull) and<script>tags on pages withReferrer-Policy: no-referrergive no host to compare against. - Fix: Serve the page from a real web address, and use
strict-origin-when-cross-originor something more permissive as the Referrer-Policy.
You set domains under Keys. See Browser keys and allowed domains.
browser_key_scope
- Cause: A domain-locked key may only do address lookups.
/api/v1/enrich/…,/api/v1/datavask/parseand/api/v1/stats/nationalare refused because they fetch data from public registers with a shared key. - Fix: Make the call from your own server with a key without domains, and pass only what the page needs on to the browser.
sandbox_scope
- Cause: A test key (
dawa_test_…) was used on/api/v1/enrich/…,/api/v1/datavask/parseor/api/v1/stats/national. - Fix: Use a live key for those endpoints. See Test keys and the sandbox.
key_blocked
A live key used from many different IP addresses in one day looks like a leaked key: it sits in a public app, in frontend code or in a repository. The sequence is:
- The first day, responses get the header
X-Danadresse-Key-Status: warnand you get an email. Calls still work. - If the pattern continues after 72 hours, the key is blocked. Responses get
X-Danadresse-Key-Status: blockedand status 403 withkey_blocked.
{
"type": "ForbiddenError",
"title": "This API key is blocked: it was used from … or more different IP addresses in one day — the pattern of a leaked key. …",
"details": {
"fix": "https://danadresse.dk/dashboard/keys",
"page_host": "shop.firma.dk"
},
"code": "key_blocked"
}details.page_host is included when the calls come from a web page. The key has then usually been put in frontend code.
Fix:
- If the key is used in a browser, set Allowed domains on it. Domain-locked keys are not covered by leak control, because each visitor has their own IP.
- If the key has leaked, create a new one under Keys, switch to it and delete the old one. See Rotate keys without downtime.
- If you run many servers behind changing IPs, write to us through support.
Test keys are not covered by leak control.
ip_not_allowed
{
"type": "ForbiddenError",
"title": "This API key is locked to specific IP addresses and this request came from 203.0.113.7. Add the address under API-nøgler → Tilladte IP-adresser.",
"details": {"ip": "203.0.113.7"},
"code": "ip_not_allowed"
}IP locking is available on Enterprise. details.ip is the address the API saw.
- The server reaches the internet through a different address than the one on the list (NAT, a new load balancer, a new cloud region).
- The server uses IPv6 and the list only has IPv4, or the other way round.
- Outgoing IPs on serverless and PaaS change often. Use a network with a fixed outgoing IP.
Add the address or network under Keys.
account_suspended
- Cause: The whole account is suspended, for example because of a missing payment or abuse. Every key gets the same error, and so does login to the dashboard.
- Fix: Write to us through support.
forbidden
{
"type": "ForbiddenError",
"title": "Blocked: abuse detected. Contact support if this is an error.",
"details": null,
"code": "forbidden"
}- Cause: Our abuse filter has blocked the IP address, for example after attempts to fetch files such as
/.envor attack patterns in the URL. The block applies to every call from that IP, whatever the key. On the DAWA paths the response has the DAWA format shown above, on/api/v1it is{"error": {"code": "forbidden", …}}. It carriesAccess-Control-Allow-Origin: *, so browser code can read the 403. - Fix: Write to us through support with the IP address and the time.
Next steps
Related guides
Markdown source Spotted an error? Tell us API-reference (Swagger)