Monitor usage with the X-RateLimit headers
Read quota and per-minute limit from the response headers, log and alert at 80 percent, and use the usage page in the dashboard.
You want to know you are approaching the quota before calls start failing or costing extra. Every response says how much is left, so your own code can keep watch without extra calls.
There is no REST endpoint that returns usage per key. You have two sources: the headers on every response and the Usage page in the dashboard. If you use our MCP server, its quota_status tool also shows the month's usage. /api/v1/stats is something else. It holds public counts of how many addresses, streets and postcodes we have, and says nothing about your usage.
The headers
Every call with a valid key has these headers:
| Header | Content |
|---|---|
X-RateLimit-Limit | The monthly quota of the bucket the call counts in |
X-RateLimit-Remaining | What is left of the monthly quota after this call |
X-RateLimit-Reset | Unix timestamp (seconds, UTC) of when the month resets: the 1st of next month at 00:00 UTC |
X-RateLimit-Minute-Limit | Calls per minute, or unlimited on Enterprise |
X-RateLimit-Minute-Remaining | What is left in the current minute |
X-RateLimit-Minute-Reset | Unix timestamp of when the minute resets |
X-Quota-Grace | true when a free account is over its quota and served from the grace buffer |
X-Quota-Remaining | Calls left in the grace buffer. Only together with X-Quota-Grace |
X-Danadresse-Key-Status | Only present when the key is flagged: warn or blocked |
Which bucket a call counts in depends on the key:
- On the free plan (Hobby) all live keys of the account share one monthly quota of 2,000 calls.
- On paid plans each key has its own counter.
- Test keys are counted per IP address at the free plan's level. See Test keys and sandbox.
- Calls from the MCP server have their own quota, and the headers then show the MCP quota.
On the free plan there is a grace buffer after the quota. When X-RateLimit-Remaining is 0, you are still served up to 2,400 calls, with X-Quota-Grace: true and X-Quota-Remaining. Once the buffer is used, the API answers 429 quota_exceeded until next month. On paid plans you can continue past the quota, and the extra calls are invoiced. X-RateLimit-Remaining stays at 0 for the rest of the month. If you want a ceiling on overage, set a budget cap under Billing. Refused calls (429) are not counted as usage. The per-minute limit is hard on every plan except Enterprise.
See the headers from the terminal:
curl -s -D - -o /dev/null "https://api.danadresse.dk/postnumre/8000" \ -H "X-Api-Key: $DANADRESSE_API_KEY" | tr '[:upper:]' '[:lower:]' | grep -E '^x-(ratelimit|quota|danadresse)'
Read the headers in your code
Read them on every response you get anyway, and pass the numbers to your logging or metrics system. The example computes how much of the month is used and warns at 80 percent:
import os from datetime import datetime, timezone import requests ALERT_AT = 0.8 def usage(r: requests.Response) -> dict: h = r.headers limit = h.get("X-RateLimit-Limit", "") left = h.get("X-RateLimit-Remaining", "") if not (limit.isdigit() and left.isdigit()): return {} limit, left = int(limit), int(left) return { "limit": limit, "left": left, "share": (limit - left) / limit if limit else 0.0, "resets": datetime.fromtimestamp(int(h.get("X-RateLimit-Reset", "0")), timezone.utc), "minute_left": h.get("X-RateLimit-Minute-Remaining"), "key_status": h.get("X-Danadresse-Key-Status"), } r = requests.get( "https://api.danadresse.dk/postnumre/8000", headers={"X-Api-Key": os.environ["DANADRESSE_API_KEY"]}, timeout=10, ) u = usage(r) print(f"used {u['share']:.1%} of {u['limit']} calls, {u['left']} left, resets {u['resets']:%Y-%m-%d}") print(f"left in this minute: {u['minute_left']}") if u["share"] >= ALERT_AT: print("WARNING: more than 80 % of the monthly quota is used") if u["key_status"]: print(f"WARNING: the key is flagged as {u['key_status']} - see /dashboard/keys")
In a real service the alert should only go out once per month. Use the X-RateLimit-Reset value as the key: if you already alerted for that value, do not alert again. Here is the same as a small fetch wrapper in Node that passes the alert to your own function:
const alertedFor = new Set(); export async function danadresseFetch(url, init = {}, alert = console.warn) { const res = await fetch(url, { ...init, headers: { ...init.headers, "X-Api-Key": process.env.DANADRESSE_API_KEY }, }); const limit = Number(res.headers.get("x-ratelimit-limit")); const left = Number(res.headers.get("x-ratelimit-remaining")); const reset = res.headers.get("x-ratelimit-reset"); if (limit > 0 && Number.isFinite(left) && (limit - left) / limit >= 0.8 && !alertedFor.has(reset)) { alertedFor.add(reset); alert(`Danadresse: ${limit - left} of ${limit} calls used this month`); } const status = res.headers.get("x-danadresse-key-status"); if (status) alert(`Danadresse: the key is flagged as ${status}`); return res; }
If you run several processes, send the numbers to one shared place (Prometheus, Datadog, a database table) instead of alerting from each process.
Per-minute headroom
X-RateLimit-Minute-Remaining is the number that matters for batch jobs. When it gets close to 0, pause until X-RateLimit-Minute-Reset instead of running into 429. The limit is 360 calls per minute on Hobby, 1,700 on Basis and 7,000 on Pro.
import time def wait_if_needed(r, reserve: int = 5) -> None: """Call after each response in a batch job. Pauses before the minute limit is hit.""" left = r.headers.get("X-RateLimit-Minute-Remaining", "") reset = r.headers.get("X-RateLimit-Minute-Reset", "") if left.isdigit() and reset.isdigit() and int(left) <= reserve: time.sleep(max(0, int(reset) - time.time()) + 0.5)
In the browser
If you call the API from a web page, your script can read every X-RateLimit-* header, X-Quota-Grace, X-Quota-Remaining and Retry-After. They are exposed through CORS. X-Danadresse-Key-Status is not, but domain-locked browser keys are never flagged as leaked either. For monitoring it is still best to collect the numbers on the server side or look in the dashboard, because in a browser the numbers only reach the visitor, not you.
The usage page in the dashboard
Usage shows the account's calls and errors per day for the last 30 days, the total and the busiest day. The numbers cover the whole account, not the single key, and they update with a small delay. Use the page to see the trend, and use the headers for alerts.
Next steps
- What to do when you hit the limit: Retries and backoff.
- Save calls: Caching address lookups.
- More room: see the plans on the front page.
Related guides
Markdown source Spotted an error? Tell us API-reference (Swagger)