Errors
Rate limits and pagination
How many requests you can make, how to read the rate limit headers, and how to page through a list.
Rate limits#
The limits protect the API from abuse. They do not limit how many messages you send: sending speed is governed per SIM, and a message that has to wait is held, not rejected (see the message lifecycle).
| What | Limit |
|---|---|
/v1, per account key |
600 requests a minute |
/v1 with a partner key acting as an account |
600 a minute per client account, 3,000 a minute per partner key |
/partner/v1, per partner key |
300 requests a minute |
POST /v1/media and POST /v1/imports |
60 a minute per account (inside the limit above) |
POST /v1/pairing-codes |
60 an hour per account, and at most 20 unused codes |
POST /v1/campaigns/{id}/estimate |
10 a minute per key and campaign |
| Failed authentications | 60 a minute per IP address; a correct key is never counted |
A batch (POST /v1/messages/batch) counts as one request.
Reading the headers#
Every response carries:
| Header | Meaning |
|---|---|
RateLimit-Limit |
Requests allowed in the current window |
RateLimit-Remaining |
Requests left in it |
RateLimit-Reset |
Seconds until the window resets |
A 429 answer is RATE_LIMITED (or PAIRING_CODE_LIMIT_REACHED for pairing codes) and adds Retry-After, the seconds to wait.
Wait that long; retrying sooner only extends the wait. Spread bulk work over time instead of bursting, and send many messages in
one POST /v1/messages/batch instead of many single requests.
Pagination#
Every list is a page and a cursor:
{
"data": [{"id": "0198f3a2-7c41-7e0b-9d52-6a1f3b8c4e10"}],
"next_cursor": "eyJpZCI6IjAxOTh..."
}
limitsets the page size, 1 to 200 (default 50).- Pass
next_cursorback ascursorto get the next page.next_cursorisnullon the last page. - A cursor is opaque and valid for 24 hours. Use it with the same filters it came from; one that is too old or does not match
answers
400 INVALID_CURSOR. Start again from the first page.
cursor=""
while :; do
page=$(curl -sS "$MYCOMM_URL/v1/messages?limit=200${cursor:+&cursor=$cursor}" -H "Authorization: Bearer $MYCOMM_API_KEY")
echo "$page" | jq -c '.data[]'
cursor=$(echo "$page" | jq -r '.next_cursor // empty')
[ -z "$cursor" ] && break
done
Comma lists in filters (status=sent,delivered) match any of the values. The sort order is part of the cursor, so do not change
sort between pages.