Skip to main content
We limit requests to protect the service and to keep a bug on your side from accidentally burning through your credits.

How the limits work

Every request goes through two checks, in this order. The first one that runs out answers 429. The per-account limit and the 300 requests/min per-IP limit are token buckets. The bucket holds as many tokens as the limit, every request spends one, and one token comes back every 60 / limit seconds. On Pro (40/min), that is one token every 1.5 seconds. In practice:
  • An integration that has been idle can spend the whole bucket in one burst.
  • The sustained rate never exceeds the published number: 40/min stays 40/min.
  • When you run out, you get capacity back in seconds, not at the next minute.
Put precisely: starting with a full bucket, up to 2 × limit − 1 requests can pass within a given 60-second span (the full bucket plus the tokens that come back during that span); over longer periods the sustained rate is the limit. The 10 requests/min per-IP limit of POST /v1/calls is still a fixed one-minute window. It gets the tighter limit because it dials a real phone; reads and the rest of the writes share the wide one.

Per-account limit by plan

The account limit is shared by every API key of the account. Creating more keys does not add throughput: five keys of the same account draw from the same bucket.
The per-IP check runs first. If all your calls to POST /v1/calls leave from a single IP (one server, one n8n instance), that IP caps you at 10 outbound calls/min even if your plan allows more. To use the full limit of Pro or Scale on that endpoint today, spread the requests across several IPs, or write to us. The other endpoints are not affected: 300 requests/min per IP is above every plan’s account limit.
If you need a sustained higher limit (a large outbound campaign, for example), write to us at team@ryvo.so and we can raise it case by case.

Rate limit headers

Every response that got past authentication carries the state of your account bucket, errors included: Read X-RateLimit-Remaining to slow down before you hit 429, instead of reacting after.

Response when you exceed the limit

The body follows the same shape as every other API error (Errors): branch on error, which is a stable code, not on message. The Retry-After header tells you how many seconds to wait before trying again. It is always at least 1. With a token bucket it is usually a few seconds: the time until the next token. A 429 can also come from our edge network, before the request reaches the API. That one may not carry the JSON body or the X-RateLimit-* headers, so branch on the status code and Retry-After, not on the body.

When we cannot check your limit

If our rate limiting store is down or too slow to answer, we refuse the request with 503 and the code rate_limit_unavailable, with Retry-After: 5 and no X-RateLimit-* headers. It means we could not check your limit, not that you used it up: do not slow down your integration because of it, just retry after Retry-After.

Best practices

For outbound campaigns of hundreds or thousands of calls, put the leads in a queue and process them with a worker that stays under your limit with some headroom (8 requests/min from a single IP, for example).
Giving n8n and your CRM different keys lets you revoke one without touching the other and tells you who made each request. It does not split the limit: all the keys of an account share it.
Combined with backoff, it guarantees that retries after a 429 do not fire duplicate calls when the first attempt succeeded but the response was lost.