Rate limits
Per-key rate buckets, the headers you can read, and back-off recipes.
Spawn rate limits are enforced per API key on two sliding windows: a 60-second bucket and a 3,600-second (1 hour) bucket. Hitting either one returns 429 rate_limited with a Retry-After header.
Read-only endpoints (GET agents, GET memory) have generous default limits and rarely hit them in practice — the limits you'll actually feel are on agent spawns.
Spawn limits per plan
| Plan | Spawns / minute | Spawns / hour | | --- | --- | --- | | Free | 5 | 30 | | Pro | 30 | 500 | | Scale | 100 | 5,000 |
These reset on a rolling window, not a fixed boundary. If you spawn 5 agents in 10 seconds on the Free tier, the 6th waits about 50 seconds before it gets through.
Per-key, not per-account
Multiple keys on the same account each get their own bucket. So a CI key and a production key don't compete. This also means you can't game limits by rotating keys faster — the underlying account quota (agent-hours/month) still applies.
Response headers
Every rate-limited response includes:
HTTP/2 429
Retry-After: 12
Content-Type: application/jsonRetry-After is the number of seconds until the current window rolls over. Always honor it.
Successful responses don't currently include X-RateLimit-Remaining style headers — they're on the roadmap for a future release.
Error response
{
"error": {
"code": "rate_limited",
"message": "Too many spawn requests. Try again in 12s.",
"details": {
"plan": "pro",
"window": "minute",
"limitPerMinute": 30,
"limitPerHour": 500
}
}
}details.window tells you whether you tripped the minute or the hour bucket. The hour bucket is what hits users running batch jobs.
Back-off recipes
Honor Retry-After (minimum viable)
spawn() {
resp=$(curl -sS -w '\n%{http_code}\n%header{Retry-After}' \
-X POST https://jettson.dev/api/v1/agents \
-H "Authorization: Bearer $JETTSON_API_KEY" \
-H "Content-Type: application/json" -d "{\"task\": \"$1\"}")
status=$(echo "$resp" | tail -2 | head -1)
if [ "$status" = "429" ]; then
retry=$(echo "$resp" | tail -1)
echo "rate-limited; sleeping $retry s"
sleep "$retry"
spawn "$1"
fi
}Bulk-spawn pacing
If you're spawning a large batch, throttle ahead of time rather than colliding with the rate-limiter:
# Pro tier — 30/min. Spawn every 2.1s with a small jitter.
for task in "${tasks[@]}"; do
spawn "$task"
sleep $(awk -v min=2 -v max=2.5 'BEGIN { srand(); print min + (max-min) * rand() }')
doneExponential back-off for 5xx
Rate limits aren't the only thing that returns Retry-After. 503 temporarily_unavailable and 503 mind_unavailable set it too. The same handler covers both.
Lifting the cap
If your use case legitimately needs higher limits — most often a Scale customer running a heavy batch job — email support@jettson.dev. Per-key rate-limit overrides are on the roadmap; we're happy to grant them ad-hoc in the meantime.
Related
- Errors — full error catalog
- Plans and quotas — the wider limit picture