Rate limits
How many requests a key may make, how to read the budget, and what to do when you run out.
Every request is counted against the key that made it. The budget is a whole number of requests per 60-second window, measured per key. It is not shared across a workspace and not tied to an IP address, so two keys in the same workspace each get the full budget.
The window starts with the first request a key makes and lasts 60 seconds from then. It does not line up with the clock minute. When it ends, the whole budget is available again, and the next request starts a new window.
Because the budget is per key, plans also cap how many live keys a workspace may hold. Within that cap, give each integration its own key, so one busy job cannot use up the budget another one needs.
Reading your budget
Every authenticated response carries the budget, so you can slow down before you reach the ceiling:
X-RateLimit-Limit: requests allowed per 60-second window for this key.X-RateLimit-Remaining: how many requests are left in the current window.
The headers are on error responses too, including the 429 itself. Two responses have no
headers, because they are sent before the limiter runs: a 401, where there is
no key to measure, and a 403 feature error for
ApiAccess, where the workspace's plan does not include the API. A plan with
no rate limit sends no headers either.
Going over
Nothing was created, so the request is safe to repeat. The body carries the limit and
nothing else: there is no reset time and no Retry-After header. Since the
window lasts 60 seconds from the key's first request in it, waiting 60 seconds after a
429 is always enough. Exponential backoff does not help here, because the budget comes
back all at once when the window ends.
# The window lasts 60 seconds from the key's first request in it, and the 429
# carries no reset time, so wait a full 60 seconds before trying again.
call_with_retry() {
for attempt in 1 2 3 4 5; do
status=$(curl -s -o response.json -w '%{http_code}' "$@")
if [ "$status" != "429" ]; then
cat response.json
return 0
fi
# The window has ended by the time this returns, and the budget is full again.
sleep 60
done
echo "Still rate limited after 5 attempts." >&2
return 1
}
The numbers
Read live from our plan catalog, so this table is what is actually enforced right now:
| Plan | API requests | Live keys | Links per month |
|---|---|---|---|
| Free | 30 / minute | 1 | 500 |
| Pro | 120 / minute | 3 | 5000 |
| Team | 600 / minute | 10 | 50000 |
| Business | 3000 / minute | 25 | 500000 |
Spending the budget well
- A bulk create is one request. Creating ten thousand links through the bulk endpoint costs a single request against the budget; creating them one at a time costs ten thousand. If you are importing, import in bulk.
- Pages hold up to 100 links. Reading a whole workspace with
size=100costs a hundredth of what reading it one link at a time would. - Cache what does not change. A link’s short URL never changes after it is created, so there is no reason to fetch it twice.
- The link allowance is counted separately. Rate limits count requests per window; the monthly link allowance counts links created. Having requests left does not mean you have links left, and the other way round.