Every API key has three independent limits. Understanding how they interact makes it easy to run at high throughput without tripping errors.

The three limits

Request rate

How many API calls you can make per unit of time.

Sync concurrency budget

How many synchronous captures can run inflight at once.

Async admission queue

How much queued async work your key can hold, waiting to run.
They apply to different parts of the flow:
  • Request rate gates every submit you send, regardless of mode. Send too fast and calls are rejected before any work starts.
  • Sync concurrency budget applies to synchronous captures — the single-surface default, ?mode=sync, the Prefer: wait=30 header, and the POST /v1/search/:surface alias. Each inflight sync capture consumes one unit of the budget until the Envelope returns.
  • Async admission queue applies to asynchronous jobs — multi-surface submits, submits with a webhook, and ?mode=async. Each submission is admitted into a queue with a fixed depth; children run as capacity frees up.
Async is the throughput path. Because work sits in the admission queue and drains as capacity opens, you can submit large batches without holding open connections. Prefer async + webhooks for volume.

Concurrency by plan

Every key’s limits are set by its plan. The sync concurrency budget is the one that scales by plan — request rate stays flat at 1,000 req/s on every tier.
Limits are per API key, and a key’s plan is your account’s plan — not per-request. A restricted key with no active subscription is limited at the Free tier. Upgrading your plan raises the sync concurrency budget and async queue capacity immediately; the request-rate ceiling doesn’t change. See pricing to compare plans.

The 429 codes

When you hit a limit, the response is 429 with a machine-readable code. Each fires for a different reason. See Errors for the full error shape and other codes.

Rate-limit headers

All 429 responses carry a Retry-After header (seconds to wait) plus the standard rate-limit trio:
Retry-After
integer
Seconds to wait before retrying. Always honor this value.
X-RateLimit-Limit
integer
The request-rate ceiling for your key in the current window.
X-RateLimit-Remaining
integer
Requests left in the current window.
X-RateLimit-Reset
integer
When the window resets (epoch seconds).
Successful submits (and 4xx rejections on the submit path) carry the same X-RateLimit-* trio, plus concurrency headers so you can see budget pressure before you get a 429:
X-Concurrency-Limit
integer
Your sync concurrency budget.
X-Concurrency-Running
integer
Sync captures currently inflight.
X-Concurrency-Queued
integer
Async work currently waiting in the admission queue.

A live inflight picture

GET /v1/async/status returns a real-time snapshot for your key: admission queue depth and capacity, sync concurrency budget in use, and inflight children grouped by region. Poll it when you want to pace submissions against actual headroom rather than reacting to 429s.
The same pattern works for the synchronous endpoints — just retry on CONCURRENCY_LIMIT_EXCEEDED the same way you retry on rate limits.

Async status

Live queue depth, budget, and inflight children for your key.

Errors

Every error code and response shape, including the 429s.

Webhooks

Get completions pushed to you instead of polling.

Asynchronous jobs

The high-throughput submission path.