Skip to content

Rate limits & errors

Rate limits

API requests are rate-limited per API key, using a sliding 60-second window backed by Redis.

Plan Requests per minute
Growth 60
Enterprise 300

Each request to any /api/v1/* endpoint counts as one unit. There's no separate read vs write quota.

When you hit the limit

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 23

{"error": "rate_limited", "message": "Rate limit exceeded. Retry after 23 seconds."}

The Retry-After header tells you how many seconds to wait before the next request will succeed. Honour it.

  • Honour Retry-After. Sleep at least that many seconds before retrying.
  • Cap concurrency. A single key with 60 req/min can sustain ~1 req/second; running 10 parallel workers against the same key will hit the limit immediately.
  • Use multiple keys if you have multiple consumers. One key per consumer makes it obvious which workload is misbehaving and lets you revoke without breaking the others.
  • Page in larger chunks rather than making many small requests. per_page=200 is the max; use it.

Example back-off in Python

import time
import httpx

def get_with_backoff(client: httpx.Client, url: str, **kwargs):
    for attempt in range(5):
        r = client.get(url, **kwargs)
        if r.status_code == 429:
            wait = int(r.headers.get("Retry-After", "5"))
            time.sleep(wait)
            continue
        r.raise_for_status()
        return r
    raise RuntimeError(f"Gave up after 5 attempts on {url}")

Error responses

All errors return JSON in a consistent shape:

{"error": "code", "message": "human-readable explanation"}

The error field is a stable machine code suitable for branching on. The message is for humans and may change wording over time.

Status codes you should expect

Code Meaning
200 Success
400 Bad input — invalid filter value, malformed date, etc.
401 Missing or invalid Authorization header
403 Authenticated but not allowed (e.g. plan doesn't include API access)
404 Resource doesn't exist or belongs to another account
422 Validation error (e.g. note too long)
429 Rate-limited
500 Our server error — retry with backoff; check the status page
502 / 503 / 504 Transient — retry with backoff

Common error codes

Code Status When you'll see it
missing_authorization 401 No Authorization header
invalid_token 401 Token doesn't match any active key
revoked_token 401 Token was revoked
plan_required 403 API isn't available on Free/Starter
not_found 404 Resource doesn't exist, or isn't yours
invalid_status 400 Bad ?status= value
invalid_date_from 400 Bad ?date_from= format
invalid_date_to 400 Bad ?date_to= format
rate_limited 429 Over your per-minute quota

Cross-account isolation

CredWatch is multi-tenant. Your API key only sees data belonging to your account.

If you request a resource ID that exists but belongs to another account, you'll get a 404 not_found — not a 403. We deliberately don't tell you "this exists but you can't see it" because that would leak the existence of other accounts.

Timeouts

  • Server-side: requests are processed synchronously and should return in under 5 seconds for any list query. If you see consistent timeouts on small queries, check the status page.
  • Client-side: set a 15–30 second timeout in your HTTP client.

Logging

Every API call hits our request log. If you're debugging a workflow and something is misbehaving, email [email protected] with:

  • Your account slug
  • The approximate time (UTC) of the failing request
  • The HTTP status and error code you got
  • What you were trying to do

…and we can pull the server-side log.