Rate limits
Two sliding-window limiters guard the API, and a request has to pass both. Tripping either limiter starts a block period longer than the window. Back off on the first rejection; retrying during the block does not shorten it.
v3 (/api/v3/*)
Every v3 endpoint sits behind both buckets. The table says what each one is
keyed by; on DELETE the second bucket is shared by every token at your address:
| Method | First bucket | Keyed by | Second bucket | Keyed by |
|---|---|---|---|---|
GET | 3,000 per 5 minutes | token | 3,000 per 5 minutes | token |
POST | 500 per minute | token | 200 per minute | token |
PATCH | 100 per minute | token | 200 per minute | token |
DELETE | 200 per 10 minutes | token | 200 per 10 minutes | client IP |
So one token gets 3,000 GET per 5 minutes and 200 POST and 200 PATCH per
minute. Where a limit is keyed by IP, every token calling from the same address
shares it — plan for that on a NAT'd fleet.
Limits are the same on every plan. If your integration needs more, contact support with what you are building.
Every admitted v3 response carries your remaining budget:
| Header | |
|---|---|
X-RateLimit-Limit | requests allowed in the window |
X-RateLimit-Remaining | requests left in it |
X-RateLimit-Reset | seconds until the window resets |
Pace off X-RateLimit-Remaining rather than waiting for a rejection. On a
429, read Retry-After and ignore any X-RateLimit-* values it carries.
Over the limit
GET, POST, PATCH and DELETE all answer 429, with Retry-After and an
RFC 7807 body:
Code
Code
The header and the body's retryAfter carry the same number of seconds. Read
either. The body is RFC 7807 in shape and is served as application/json, like
every other response — see Errors.
v1.0 (/api/v1.0/*)
| Method | Per token | Per IP |
|---|---|---|
GET | 1,000 per 5 minutes | 200 per minute |
POST | 50 per minute | 100 per minute |
PUT | 50 per minute | 100 per minute |
DELETE | 10 per minute | 200 per 10 minutes |
POST /messages | 500 per 5 minutes | 100 per minute |
Over the limit:
Code
Code
Retry-After is the remaining block time, not the remaining window, and the
blocks are long: 60 minutes after exhausting the per-token GET or POST /messages bucket, 10 minutes after the other per-token buckets, 10 minutes
after the per-IP GET bucket and 60 minutes after the other per-IP ones.
POST /oauth/token
Both token endpoints have their own per-IP limiter, and the two are not the same:
| Endpoint | Limits |
|---|---|
api.niftypm.com/oauth/token — the OAuth 2.1 server | 120 per minute |
openapi.niftypm.com/oauth/token | 120 per minute and 1,000 per hour |
Neither has a block period — a client that briefly spikes recovers within one
window. Over the limit both answer 429 with Retry-After and an RFC 6749
body:
Code
Backing off
- Respect
Retry-After/retryAfter. It is an exact number of seconds, not an estimate. - If neither is present, sleep 1 second and double on each attempt, giving up after 5 retries.
- Add jitter, so a fleet of workers that tripped together does not retry together.
- Never blind-retry a
POSTwithout anIdempotency-Key— see Getting started. - Spend fewer requests rather than pacing more: one paginated
LISTbeats NGETs by id, and?expand=beats a follow-up request per relation.