Developers Rate limits

Developers

Rate limits

Frontpage Public API rate-limit classes, windows, Retry-After behavior, CLI exit codes, and which commands hit which bucket.

How limiting works

Every /api/v1/* call is counted against a fail-closed rate limiter (KV-backed). When a bucket is exhausted the API returns HTTP 429 with envelope code rate_limited and a Retry-After header (seconds). The CLI maps that to exit code 2.

If the rate-limit store is unavailable, the API fails closed with HTTP 503 (unavailable) rather than allowing unlimited traffic. That is also exit 2 or 5 depending on how the CLI classifies the error — always prefer --json and read error.code.

Rate limits are separate from plan AI/bandwidth budgets. Hitting a 429 does not mean you are out of AI credits. Check frontpage usage for plan meters, and this page for request throttling.

Classes

Class Limit Window Bucket key
RL-AUTH 30 1 minute Client IP (failed / missing Bearer)
RL-READ 120 1 minute API key id
RL-WRITE-LIGHT 30 1 minute API key id
RL-SYNC-PULL 10 1 minute API key id
RL-SYNC-PUSH 6 1 minute API key id (+ site slug)
RL-PUBLISH 5 10 minutes API key id + site slug
RL-AGENT 20 10 minutes API key id + site slug
RL-AGENT-CTRL 40 10 minutes API key id + site slug
RL-MINT 5 24 hours User id (session cookie — key creation in the editor)

Successful authenticated calls also consume an RL-AUTH check during key verification, then the route’s success class (for example RL-READ). Failed auth is charged only to RL-AUTH by IP so credential stuffing cannot burn a valid key’s read budget.

CLI command → class

CLI commands Class
whoami, sites, doctor, ls, cat, search, status, diff (one list read; blobSha compare), history, runs / runs get / runs list / runs current, usage, analytics (dashboard GET + ops POST), pages, modules (list|docs), extensions (list|docs), fonts, media list, inbox (read), seo get, articles list, articles content get, settings get RL-READ
pull RL-SYNC-PULL
push, tokens set RL-SYNC-PUSH
edit, seo set, settings set, media upload, articles mutations, modules / extensions enable|disable|config|archive|request-setup, inbox … --mark-read, revert RL-WRITE-LIGHT
prompt (enqueue a new agent run) RL-AGENT
runs cancel, runs retry RL-AGENT-CTRL
publish, unpublish RL-PUBLISH
Create key in editor (Developers → Create key) RL-MINT (5 / 24h per user)

runs wait and deploy wait poll with read-class GETs. Aggressive tight loops can exhaust RL-READ — back off using the wait helpers rather than spinning your own 10ms poll.

429 response shape

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

{
  "ok": false,
  "error": {
    "code": "rate_limited",
    "message": "Too many requests. Try again later."
  }
}

With the CLI and --json, failures still set the process exit code. Expect exit 2 for rate limits. Honor Retry-After (or wait at least the class window) before retrying.

frontpage pull --json
# ok:false, error.code === "rate_limited" → sleep, then retry
echo $?

Key mint limit (RL-MINT)

Creating API keys is limited to 5 per user per 24 hours. Minting happens only from the editor session (profile → Developers), not via Bearer. If you hit the mint cap, wait for the window or delete unused keys and reuse an existing secret where policy allows.

Practical guidance for agents

  • Prefer pull once per work session (or when tipDrift is true); do not pull in a tight loop (RL-SYNC-PULL is 10 / min).
  • Use diff --json freely for dirty checks — it is one RL-READ list call (git blob SHA compare), not one read per file.
  • Batch local edits, then a single push (6 / min).
  • Do not fire many prompt calls in parallel (20 / 10 min per site).
  • On exit 2, check whether it is rate-limit vs plan budget (frontpage usage).

See also Errors & exit codes and Analytics & usage.