Rate limits

30 requests per minute per API key, the headers that report your window, and how to back off on 429.

Each API key can send up to 30 requests per minute, counted in fixed one-minute windows across every server of the API. Every request made with a valid key counts, reads and writes alike, including the ones answered 403, such as a plan that no longer includes the access. Every response past the key check reports the current window:

HeaderMeaning
RateLimit-LimitRequests allowed per window: 30.
RateLimit-RemainingRequests left in the current window.
RateLimit-ResetSeconds until the window resets.
RateLimit-Limit: 30
RateLimit-Remaining: 17
RateLimit-Reset: 41

Beyond the limit the API answers 429 Too Many Requests with a Retry-After header holding the seconds to wait.

{
  "ok": false,
  "timestamp": 1738247125207,
  "message": "Rate limit of 30 requests per minute exceeded"
}

Each key has its own window: one integration using up its limit does not slow down another key of the same organization.

Failed authentication

Requests that fail authentication (401) are throttled separately, per client address, before any key is looked up. After 30 failed requests in a minute, that address is answered 429 Too many failed authentication attempts until the minute ends, whatever key it sends. IPv6 addresses count by their /64.

When the limiter is unavailable

The API never serves a request it cannot count. If the rate-limit store is briefly unreachable, it answers 503 Rate limiter unavailable: retry with backoff.

Stay under the limit

  • Use limit=100 on lists. It needs half the requests of the default page size.
  • Cache the catalogs. /metrics, /prescription-types, /units, /muscles and the global part of /exercises change rarely. Load them once and look ids up locally.
  • Filter on the server. Use userId, from and to instead of downloading everything and filtering yourself.
  • Read RateLimit-Remaining and slow down before it reaches zero, instead of waiting for a 429.
  • Do not parallelize without a ceiling. A few concurrent requests are fine. Hundreds are not.

Back off on 429

Wait Retry-After seconds, then continue where you stopped. Do not retry immediately: each retry also counts against the current window and keeps answering 429 until it resets.

# curl has a built-in retry for 429, 500 and 503
curl --retry 5 --retry-all-errors \
  "https://api-next.vitruve.fit/v1/athletes" \
  -H "X-API-Key: YOUR_API_KEY"

On this page