Rate Limits

Last updated 2 days ago

j17 applies rate limits at two layers: per-instance limits to ensure fair sharing between tenants, and plan-based limits to enforce your billing tier. Both return 429 Too Many Requests when exceeded, with headers and response bodies that tell you exactly what happened.

Per-instance limits

Every instance has a burst rate limit determined by its billing tier. This limit applies across all API keys for the instance — creating more keys doesn't increase your throughput.

Write limits

Tier Limit Per second
Free 600/min 10/s
Hobby 6,000/min 100/s
Pro 12,000/min 200/s
Scale 60,000/min 1,000/s

Read limits

Read limits are 5x write limits. Reads are cheaper but a runaway polling loop can still affect performance for other tenants.

Tier Limit Per second
Free 3,000/min 50/s
Hobby 30,000/min 500/s
Pro 60,000/min 1,000/s
Scale 300,000/min 5,000/s

Response

When you exceed your instance limit:

HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 6000
X-RateLimit-Remaining: 0
X-RateLimit-Scope: instance
X-RateLimit-Tier: hobby

{
  "ok": false,
  "error": "Rate limit exceeded",
  "scope": "instance",
  "limit": 6000,
  "window": "1m",
  "tier": "hobby"
}

Successful responses include X-RateLimit-Remaining so your client can self-throttle before hitting the limit.

What to do

  • Batch writes. Use POST /:type/:id with an array of events instead of individual requests. One batch counts as one request.
  • Upgrade your tier. Tier changes take effect within 30 seconds.
  • Backoff. When you get a 429, wait before retrying:
const delay = Math.min(1000 * 2 ** attempt, 30000) + Math.random() * 1000;
await new Promise(r => setTimeout(r, delay));

Per-IP safety net

A global per-IP limit of 30,000 requests/minute acts as a safety net. You should never hit this under normal use — if you do, the X-RateLimit-Scope header will say ip instead of instance.

Plan limits

Your plan includes a monthly allocation for events written. As you approach and exceed it:

Usage Behavior
Under 80% Normal operation
80-100% Requests succeed but include a warning header
Over 100% Requests rejected with 429

Warning (approaching limit)

HTTP/1.1 200 OK
X-J17-Limit-Warning: Approaching events_written limit: 800/1000

Watch for the X-J17-Limit-Warning header and alert before you hit the hard limit.

Hard limit (exceeded)

HTTP/1.1 429 Too Many Requests
X-J17-Limit-Exceeded: events_written: 1250/1000

{
  "ok": false,
  "error": "Limit exceeded",
  "metric": "events_written",
  "usage": 1250,
  "limit": 1000,
  "message": "You have exceeded your plan's events_written limit. Please upgrade your plan or wait until the next billing period."
}

Plan limits count monthly totals. Rate limits count per-minute bursts. They are independent — you can be within your monthly allocation but exceed your burst limit, or vice versa.

Read operations

Read operations (GET /:type/:id, GET /_projections/* on the worker) count against your instance's read rate limit but are not counted against your plan's event allocation. Only writes count toward plan limits.

Size limits

Separate from rate limits, j17 enforces payload size limits:

Limit Value
Max event data size 100 KB
Max batch size 10,000 events per request
Max spec size 1 MB

Exceeding these returns 413 Request Entity Too Large.

See also

Can't find what you need? support@j17.app