Rate limits
The hourly quota, the abuse controls in front of it, the headers that report them and how to pace a client.
Four controls sit inside the API, and an edge throttle sits in front of them. One is your plan’s budget; the others keep a single client from degrading the service for everyone. Only the budget is reported in headers, because only the budget is something a well-behaved client will ever reach.
The hourly quota
Your organization’s key requests share one budget per clock hour (UTC), reset at the top of the hour.
| Plan | Requests per hour |
|---|---|
| Hobbyist | No API access: a key on this plan is refused with 401. |
| Pro (including a Pro trial) | 1,000 |
| Enterprise | No hourly quota. Usage is still recorded per key, and the per-address limits below still apply. |
Every request that reaches the quota is counted, whatever the handler then
does: a 404, a 405 or a permission 403 spends budget like a 200.
Requests rejected before the quota, by an abuse control below or because the
key is bound to another organization, are not counted.
Headers
Every metered response carries these headers. Only requests that authenticate with an API key are metered; dashboard sessions carry none of these headers and spend nothing. On an unlimited plan none are sent either, because a limit of zero would read as no budget at all.
| Header | Meaning |
|---|---|
X-RateLimit-Limit | The hourly budget. |
X-RateLimit-Remaining | Requests left in the current hour. |
X-RateLimit-Reset | Unix time (seconds) at which the budget resets. |
RateLimit-Policy | The same budget as an IETF structured field, for example "hourly";q=1000;w=3600. |
RateLimit | The same remaining count and seconds-to-reset: "hourly";r=<remaining>;t=<seconds>. |
Retry-After | Only on a rejection: seconds until the reset. |
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1767229200
RateLimit-Policy: "hourly";q=1000;w=3600
RateLimit: "hourly";r=999;t=1800 Reading a 429
A 429 from the API carries a code so a client can tell the remedies apart;
one from the edge carries nothing:
code | Cause | Remedy |
|---|---|---|
quota_exceeded | The hourly budget is spent. | Wait until X-RateLimit-Reset. Backing off sooner does not help. |
rate_limited | An abuse control rejected the request. | Sleep for Retry-After seconds and retry. No quota headers are sent, because no budget was touched. |
| no JSON body | The client address was throttled at the edge before reaching the API. | Back off exponentially; there is no header to read. |
Abuse controls
These are sized so a real client never meets them. They exist for loops that have gone wrong.
- Per address, before authentication. 300 requests per minute from one client address, counted before the key is checked and whatever the plan. A flood of bad keys is stopped before it costs a lookup. This bucket is shared by every request from that address, dashboard sessions included, so a revoked key in a tight loop can lock an office or a CI runner out for a minute.
- Heavy routes. Endpoints marked
heavy route in the reference run expensive aggregations or reach out
to DNS. Across all of them, an organization’s keys get
120 requests per hour. This hour starts at your
first heavy request rather than at the top of the clock hour, no header
reports what is left of it, and the
Retry-Afteron its429can run to the end of that hour. Cache these responses. - Concurrency-capped routes. The heavy routes marked
concurrency-capped may only run a few at a time per organization. A
request that cannot get a slot within a couple of seconds gets
503withRetry-After. Those slots are shared with people using the dashboard in your organization, so a tight polling loop can slow your own team down.
In front of all of them, the edge caps bursts and concurrent connections per
client address. A client that trips it receives 429 with no body and no
headers until its rate drops. Abuse that puts the service at risk is covered by
the Terms, but we would rather hear from you first: if you have a
legitimate reason to exceed these limits, such as a one-time backfill, write to
contact@dmarcguard.io before you start.
Pacing a client
- Read
X-RateLimit-Remainingand slow down before it reaches zero, rather than retrying on429. - Spread scheduled work across the hour instead of running everything at the top of it, when the budget has just reset for every other client too.
- Prefer one aggregated call to many small ones: the organization overview and domain health endpoints already join what a dashboard needs.
- Use
limitup to 200 when paging; more rows per request means fewer requests.