REST API
Rate limits
Each REST key has its own request buckets. The headers on each response show the limit, what is left and when it refills.
Buckets
Requests are counted in buckets. A bucket holds a number of requests and refills at a steady rate, so a short burst is fine as long as the average stays under the rate. Each REST key has its own buckets. Two keys on one server do not share them.
| Bucket | Counts | Refills | Holds |
|---|---|---|---|
send |
Each POST that does not name a segment or a tag, such as a list of ids |
50 a second | 100 |
broadcast |
Each POST to included_segments or tag |
30 a minute | 10 |
read |
Each GET /api/v1/notifications/{id} |
20 a second | 40 |
audience |
Sends to the same segment or tag on one app, from any of its keys | 10 a minute | 10 |
ip |
Every call with a valid key from one IP address, across keys | 6,000 a minute | 6,000 |
anonymous |
Calls from one IP address that return 401 or 403 |
120 a minute | 120 |
A call draws from ip first, then from its key's send, broadcast or read bucket, then, for a segment or tag send, from audience. A call that one bucket refuses does not draw from the buckets after it. A call with a missing, wrong or IP-locked key draws only from anonymous, never from a key's buckets.
Headers
Each response carries the bucket closest to running out, and the list of buckets the call drew from:
RateLimit-Limit: 100
RateLimit-Remaining: 99
RateLimit-Reset: 1
RateLimit-Policy: 6000;w=60;burst=6000;name="ip", 50;w=1;burst=100;name="send"
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 99
X-RateLimit-Reset: 1792310401
| Header | Meaning |
|---|---|
RateLimit-Limit |
How many requests that bucket holds. |
RateLimit-Remaining |
Requests left in that bucket. |
RateLimit-Reset |
Seconds until that bucket is full again. |
RateLimit-Policy |
Each bucket the call drew from: requests per window, w the window in seconds, burst how many it holds, and name. |
X-RateLimit-Limit |
The same as RateLimit-Limit. |
X-RateLimit-Remaining |
The same as RateLimit-Remaining. |
X-RateLimit-Reset |
A Unix timestamp in seconds: when that bucket is full again. On a 429 it is the moment Retry-After runs out, that is now plus Retry-After. |
Over the limit
Over the limit, the call returns 429 with a Retry-After header, in seconds, and the headers above for the bucket that refused it:
{ "message": "Too many requests. Retry after 1 second." }
Wait for Retry-After, then retry. Send an Idempotency-Key so that a retried send cannot go out twice. A replayed call counts against the buckets like any other call.
Size limits
| Limit | Value | Over the limit |
|---|---|---|
| Ids per list | 500 | A list of more than 500 Subscription IDs or External IDs returns 422. |
| Devices per send | 1,000,000 | A segment or tag send reaches every matching subscribed install, up to 1,000,000. A larger audience returns 422 with "This send reaches 1,200,000 devices. One send reaches at most 1,000,000." |
| Throttle | 1 to 100,000 a minute | 422 with "throttle_rate_per_minute is a whole number from 1 to 100000." |
| Message | 2,000 characters | 422 |
| Title | 120 characters | 422 |
| Apple payload | 4KB, checked with the longest language | 422 with "This notification is larger than 4KB." It is not cut short. |
| Link | 500 characters | 422 |
| Buttons | 1 | 422 with "Send one button." |
| Data | Keys up to 40 characters, values up to 2,000 | Longer keys and values are cut to that length. |