SurfacedBySurfacedBy Docs
DocumentationReference

Rate Limits

Per-key quotas, response headers, 429 semantics, and Retry-After behaviour.

Ask an AI:Open in ChatGPTOpen in Claude

The SurfacedBy APIs are rate-limited per key, in two fixed windows: per UTC clock minute and per UTC calendar month. Exceeding either returns a 429 response.

Quotas

APIPer minutePer month
Agency plan (Data API)6050,000
Professional plan (Data API)6010,000
Console API (per key)120100,000

On the Data API the quota follows the plan of the key's workspace. Each key has its own counters: several keys in one workspace do not share a pool, and test keys count separately from live keys.

Response headers

Successful responses include:

  • X-RateLimit-Limit-Minute - the per-minute limit for this key.
  • X-RateLimit-Remaining-Minute - requests left in the current minute.
  • X-RateLimit-Limit-Month - the per-month limit for this key.
  • X-RateLimit-Remaining-Month - requests left in the current month.

A 429 response carries Retry-After instead: the seconds until the current minute ends when you exceeded the per-minute limit, or 3600 when you exceeded the monthly limit.

429 response shape

The body is a standard problem document (see Errors):

{
  "type": "https://docs.surfacedby.com/v1/api/errors#rate_limited",
  "title": "Rate limit exceeded",
  "status": 429,
  "detail": "Your key has exceeded its per-minute request limit.",
  "request_id": "req_...",
  "limit_window": "per-minute",
  "scope": "professional"
}

limit_window tells you which window you exceeded.

Window behaviour

Both windows are fixed, not rolling or token buckets. When a new minute or month starts, the budget resets to the full allowance. Every request that reaches the limiter counts, including requests that then fail, so a client that keeps retrying a failing request spends its budget.

503 rate_limit_unavailable

If the rate limiter itself is unavailable, the API refuses the request with a 503 and Retry-After: 30 rather than serving it unmetered. Treat it like a 429 for retry purposes.

Designing around the limits

  • Follow each list to its last page with the cursor rather than re-reading the first page.
  • Cache on your side. Analytics change when a Daily Check or Full Check completes, so polling more than a few times a day spends budget without returning new data.
  • Use webhooks to learn when a check completes instead of polling.

On this page