Limits
Every limit the API enforces, in one place. If you are sizing a backfill script, skip to sizing an import.
Rate limits
Section titled “Rate limits”Counted in fixed one-minute windows, per tenant. A rejected request returns
429 with code RATE_LIMITED and a Retry-After header in seconds — respect
it rather than retrying immediately.
| Window | Limit | Applies to |
|---|---|---|
| Tenant | 10,000 requests/min | every authenticated request — user tokens and server tokens together |
| Batch | 600 requests/min | /v1/batch/* only, on its own window |
| Auth failures | 20 failures/min per IP | requests that fail authentication |
The batch window is separate on purpose: a running import cannot starve your app’s normal traffic, and a traffic spike cannot stall your import. Batch calls do not also charge the tenant window.
Only genuine auth failures count against the IP limit — a 429 or an internal
error does not. That limit exists to make credential-guessing expensive, so it
is per IP rather than per tenant.
Payload caps
Section titled “Payload caps”| Cap | Value |
|---|---|
| Items per batch call | 100 (/v1/batch/users, /follows, /activities) |
Page size (limit) |
100 max, 20 default |
| User token TTL | 24h max, 1h default |
| Live promoted activities per tenant | 100 — an abuse guard, not a plan limit; retracted rows do not count |
| Promoted rows per feed sidecar | 10, newest first |
refs per activity |
4 — objects one activity points at |
Feed refs per promoted audience |
20, matched with OR — a different thing: the feeds a promoted activity targets, not objects |
Keep user tokens short. The 24h ceiling is an upper bound, not a
recommendation — mint them per session, and use
revokeUserTokens when a user logs out or is banned.
Sizing an import
Section titled “Sizing an import”The batch window is the binding constraint, and it is generous: 600 calls/min × 100 items = 60,000 items per minute. In practice you will hit your own database read speed first.
Concretely, for a backfill of N items:
calls = ceil(N / 100)minutes = calls / 60050,000 follow edges is 500 calls — under a minute of wall clock at the limit, and comfortably inside it at any sane concurrency. A few thousand users’ worth of history does not come close.
Two rules that matter more than the arithmetic:
- Serial is usually fine. Concurrency above ~10 in-flight calls buys little
and makes a
429more likely. Start serial, measure, then raise it. - Handle
429by sleepingRetry-After, not by retrying in a tight loop. A batch call is safe to replay when activities carryforeign_id+time(see Idempotency).
Not limited
Section titled “Not limited”There is no cap on the number of users, feeds, follow edges, or activities in a tenant, and no per-feed follower ceiling. Fan-out to a very large follower count is chunked and streamed rather than refused.
Related
Section titled “Related”- Migrating existing data — the import these limits govern.
- Promoted activities — where the promoted caps apply.
- Authentication & tokens — token TTL and revocation.
- Pagination — working within the page-size cap.