Okouro docs

Okouro throttles requests to keep the API responsive for everyone. Limits use a fixed time window and are enforced before most other processing.

How limits are applied

Requests are counted in a rolling window. There are three tiers:

TierApplies toCounted perDefault limit
Authenticatedall protected endpointsthe user (falls back to IP if the token is invalid)300 requests / 60s
Publicpublic routes and the MCP endpointclient IP300 requests / 60s
Credentiallogin, signup, complete-signup, refresh, accept-invitation, redeem-password-changeclient IP10 requests / 60s

The credential tier is deliberately tight to slow down brute-force attempts. GET /health is exempt from all limits.

Limits are advisory safety valves, not quotas; the exact numbers are set by server configuration and may differ from the defaults above. Read them from the response headers rather than hard-coding them.

Response headers

Every allowed response includes your current budget:

x-ratelimit-limit: 300
x-ratelimit-remaining: 297
x-ratelimit-reset: 42
  • x-ratelimit-limit - the ceiling for the window.
  • x-ratelimit-remaining - requests left in the current window.
  • x-ratelimit-reset - seconds until the window resets.

When you are limited

Exceeding a limit returns 429 Too Many Requests with a Retry-After header:

HTTP/1.1 429 Too Many Requests
retry-after: 12
x-ratelimit-remaining: 0

{ "error": "rate_limited", "message": "Too many requests; please slow down." }

Wait the number of seconds in Retry-After, then retry. Note the body here has an extra message field compared to the standard error shape.

The credential tier is the exception: to avoid revealing the brute-force threshold, a throttled credential request answers with a generic body and only a Retry-After header (no x-ratelimit-* headers):

HTTP/1.1 429 Too Many Requests
retry-after: 12

{ "error": "too many attempts; please try again later" }

Account lockout

The credential endpoints (/auth/login, /auth/register, /auth/refresh, invitation and password-change redemption) are additionally protected by a per-account lockout, independent of IP. After a small number of consecutive failed logins on one account, that account is temporarily locked and returns 429 Too Many Requests with a Retry-After header, even from different IP addresses. A successful login clears it. This complements the per-IP throttling described above; it does not replace it.

The body is the same generic “too many attempts” message as the credential-tier throttle above, so a locked account is not distinguishable from a throttled IP.

Staying under the limit

  • Batch reads with pagination. Pull larger pages (per_page up to 100) instead of many small pages. See Conventions.
  • Cache what rarely changes. Reference data such as clients and consultants does not need to be refetched on every operation.
  • Respect Retry-After on 429. Hammering a limited endpoint keeps you limited; backing off clears it.
  • Authenticate. Authenticated traffic is keyed per user, so one busy integration does not exhaust another’s budget, and it avoids the shared public IP bucket.

Fail-open behaviour

If the rate limiter’s backing store is unavailable, requests to ordinary API routes are allowed through rather than blocked. The credential endpoints fall back to an in-process limiter in that case, so brute-force protection on login is not fully lost during an outage. Either way, treat the limits as best-effort protection, not a guarantee, and still design your client to behave well under 429.