databob

Rate limits and errors

120 requests a minute per key, 600 per org, and the error codes the data API returns.

Last updated on

Edit this page

Limits are fixed windows in @convex-dev/rate-limiter, one shard, so the caps stay exact. Change the numbers in convex/lib/dataApiLimits.ts if you operate the deployment. The values below are what the code ships.

LimitValue
DATA_API_RATE_LIMIT_MAX_REQUESTS120 requests per key
DATA_API_ORG_RATE_LIMIT_MAX_REQUESTS600 requests per org
DATA_API_RATE_LIMIT_WINDOW_MS60000 (60 seconds)
DATA_API_KEYS_PER_ORG_MAX25 active keys
DATA_API_LAST_USED_MIN_INTERVAL_MS60000

The org cap stops 25 keys from multiplying the per-key cap. A request that is already over either limit returns 429 from the rate-limit read. It does not consume another token and does not change lastUsedAt.

400 and 401 are returned before the rate limit is checked and before lastUsedAt changes. 403 and 404 are decided after the request is charged. 429 includes Retry-After as a whole number of seconds. 400, 401, 403, and 404 do not.

Error codes

Every error body uses { "error": "<code>" }. message is optional and for humans. Branch on error.

400 bad_request

The query is wrong. Returned before the rate limit. No Retry-After.

400.json
{ "error": "bad_request", "message": "period must be 7d or 28d" }

Other messages from the parser:

  • Provide one content id or a batch
  • Content id batch is at most 20
  • Content id must be a non-empty string
  • project_id is not a project id
  • project_id is required for a key that can read every site

401 unauthorized

The bearer token is missing, unknown, or revoked. A dbw_ write key and a legacy dbr_ key are unauthorized here. Returned before the rate limit. No Retry-After.

401.json
{ "error": "unauthorized" }

403 forbidden

The key is valid and the site is in the same org, outside this key's scope. The request has already been charged. No Retry-After.

403.json
{ "error": "forbidden" }

404 not_found

project_id is a real id and the project is missing or belongs to another org. Both cases use this status. The request has already been charged. No Retry-After.

404.json
{ "error": "not_found" }

429 rate_limited

The key is over 120 requests, or the org is over 600, in the current 60 second window. Retry-After is a whole number of seconds. The body does not include a message.

429
HTTP/1.1 429
Retry-After: <seconds>
Content-Type: application/json

{ "error": "rate_limited" }

500 unavailable

DATA_API_KEY_PEPPER is not set on this Convex deployment. This is not a client rate limit.

500.json
{ "error": "unavailable" }

On this page