# Rate limits

Every authenticated `/v1` response carries the rate-limit headers in two forms. The IETF draft structured fields:

```
RateLimit: limit=60, remaining=42, reset=18
RateLimit-Policy: 60;w=60
```

- `limit`: the number of calls the window allows.
- `remaining`: how many you have left.
- `reset`: seconds until the counter resets.
- `RateLimit-Policy`: `<limit>;w=<window in seconds>`, so a client can pace itself without trial and error.

And the conventional trio, with the same numbers:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 42
X-RateLimit-Reset: 1791158418
```

`X-RateLimit-Reset` is the Unix time, in seconds, when the counter resets (the `reset` above is seconds from now).
When more than one limit applies to a call, both forms describe the one nearest to running out.

On 429 you also get `Retry-After` in seconds. Treat `reset` on a success as advice and `Retry-After` on a 429 as a rule.

## Keys in their own company

A key set to work in **This company** gets **60 calls a minute** of its own, within its app's ceiling (600 calls a
minute by default) across all the app's keys and companies. The count is kept per key, not per IP address, so several
integrations running from one office each get their own 60.

When the key's own limit refuses a call, the 429 says `rate_limit_scope: "app_key"` and `detail` reads "Rate limit
exceeded for this key (60 calls a minute). Retry after N seconds."

## Signed-in people and older keys

A person's own sign-in, and an older `ak_` API key, get **60 calls a minute** each, and each call counts once.

- With an older API key, the key is the counter, whichever companies it works in.
- Otherwise, the signed-in person is the counter.

## OAuth connections

A call made with an OAuth token from a client that is not an app made on the Developer page, such as ChatGPT, Claude or
Cursor, is counted per connected client and per person who connected it: **60 calls a minute** each. Other people
using the same client never use up your allowance.

## Apps in other companies

An app installed in other companies usually works for many of them. So that one busy company cannot use up the others'
allowance, the app has two limits there, whether it calls with a key set to work in every company that installed it or
with a person's OAuth token:

- **Per company: 60 calls a minute** in each company. An app working in one company keeps its allowance there.
- **Ceiling: 600 calls a minute** across all its companies together.

The company is the one the call names, with the `Exayard-Organization-Id` header or `organizationId` (see
[Authentication](https://developers.exayard.com/authentication.md)). The calls that name no company (`GET /v1/me`, `GET /v1/installations` and the
`/v1/organizations` calls) are counted per key, or per person for an OAuth token, at the per-company number, and they
count toward the ceiling too.

When one of these limits refuses an app's call, the 429 body says which in `rate_limit_scope`:

```json
{
  "type": "https://developers.exayard.com/concepts/errors#rate_limited",
  "title": "Too Many Requests",
  "status": 429,
  "code": "rate_limited",
  "detail": "Rate limit exceeded for this app in this company (60 calls a minute). Retry after 12 seconds.",
  "rate_limit_scope": "app_company"
}
```

- `app_key`: this key in its own company (see [above](#keys-in-their-own-company)).
- `app_company`: this app in this company. Other companies are not affected; slow down in this one.
- `app`: this app across all its companies. Spread the work out over time, or ask for a review.

On the MCP server the same two limits apply to apps, keyed by the company in the `Exayard-Organization-Id` header. See
[Agent rate limits](https://developers.exayard.com/concepts/ai-gateway.md).

### The review that raises them

A new app is unreviewed: the limits above, and at most 25 installs outside its own company. An admin of the app's
company asks for a review with **Ask for review**, in the menu of the app's **Let other companies install this app**
part on the Developer page. Exayard support decides:

- **Approved**: the install cap is removed, and support can raise the per-company limit and the ceiling (up to 10,000
  calls a minute each). Limits are never lowered by an approval. An approved app can also be shown in **Find apps**,
  where admins of other companies look for apps.
- **Rejected**: support leaves a note, the app goes back to the unreviewed limits and is unlisted. Existing installs
  are kept.

## Which company a call ran in

Every response to a call that names a company carries it back in the `Exayard-Organization-Id` header, errors and
429s included. With a key set to work in This company it is the key's own company. Log it next to `X-Request-Id`: when you ask
for help, the two together tell us exactly which call in which company you mean. Calls that name no company, such as
`GET /v1/me`, do not carry it. Neither do an app's `company_required`, `company_mismatch` and `app_not_installed`
refusals, which answer before the call's company is settled.

The whole API also has one shared ceiling across every caller, far above any single integration's use. It protects the
service and you should not reach it.

## Calls without working credentials

A call with no `Authorization` header, or with a key or token that does not work, is limited per IP address: **30 a
minute and 150 an hour**. These calls get a 401, so the limit only slows down guessing and broken clients.

Once an IP address has used its 30 a minute this way, calls from that address with working credentials are refused
with a 429 too, until the minute resets. If a misconfigured client shares your address, fix it, or your working calls
can be held back for up to a minute.
