---
title: "Rate limits"
description: "The hourly quota, the abuse controls in front of it, the headers that report them and how to pace a client."
publishedAt: 2026-09-14
---
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
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-After` on its `429` can 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 `503` with
  `Retry-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](/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-Remaining` and slow down before it reaches zero, rather
  than retrying on `429`.
- 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](/docs/api/v1/analytics/#getDashboardOverview) and
  [domain health](/docs/api/v1/domains/#getDomainHealth) endpoints already join
  what a dashboard needs.
- Use `limit` up to 200 when paging; more rows per
  request means fewer requests.

> **Watching usage over time**
>
> The [usage endpoint](/docs/api/v1/api-keys/#getAPIKeyUsage) and the API Keys
> screen in the dashboard show the current window, a request history (hourly for
> a window of two days or less, daily beyond) and which key is spending the
> budget.