APIRate Limits

Rate Limits

Logic64 enforces per-endpoint rate limits and generation capacity protections to ensure fair throughput for all users. When a limit is reached the API returns HTTP 429 with a Retry-After header. This page documents every published limit, what a 429 response looks like, and the backoff strategy clients should follow.

Why rate limits

Rate limits serve three purposes:

  • Fairness across users. A single client that hammers the download or repackage endpoints cannot degrade service for everyone else. Per-user windows ensure consistent throughput regardless of load distribution.
  • Capacity protection. Generation is compute-intensive. Bounding the request rate prevents any one account from exhausting server-side resources and causing latency spikes for concurrent sessions.
  • Runaway cost prevention. Generation requests trigger resource-intensive server-side work. Limits act as a circuit breaker against accidental retry loops that would otherwise accumulate costs silently.

Per-endpoint limits

Limits are enforced per authenticated user, evaluated over a rolling one-minute window. Endpoints not listed below are either explicitly not rate-limited or have no published limit.

MethodEndpointLimitNotes
GET/bundles/:idNo published limitReturns bundle metadata.
GET/bundles/:id/download10 req / min / userStreams the bundle ZIP.
POST/bundles/:id/ackNot rate-limitedIdempotent pull confirmation.
POST/projects/:id/bundles/repackage3 req / min / userRe-emits a bundle without an LLM call.

The GET /bundles/:id metadata endpoint has no published limit but is still subject to general abuse-prevention policies. The ACK endpoint POST /bundles/:id/ack is intentionally not rate-limited — retrying a failed ACK must always succeed without backoff.

429 responses

Every rate-limit rejection returns HTTP 429 with a Retry-After header. The value is in seconds and represents the minimum wait before the next request will be accepted. Clients must respect this value — retrying before the window expires will produce another 429.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/json
{
"error": "Too many requests"
}
  • Retry-After is always an integer number of seconds.
  • The response body always contains an error string for programmatic detection.
  • On repackage, the response may additionally include a code field (e.g. "TOO_MANY_REQUESTS") for structured error handling.

Generation capacity

Generation requests are processed through a server-side queue. The queue has a configured maximum depth. When the depth is exceeded — typically during sustained high demand — the API returns HTTP 429 with a Retry-After header rather than silently dropping or holding the request open indefinitely.

During high demand, new generation requests may be temporarily rejected with 429 while the queue drains. The Retry-After value indicates the recommended wait. Studio surfaces this as a “server busy” message with an automatic retry countdown.

This behavior is by design: a hard rejection at intake is preferable to accepting a request into an unbounded queue where it could wait for an indeterminate amount of time with no feedback to the caller.

Plan generation caps

In addition to per-minute endpoint limits, generation throughput is capped at the account level based on your plan:

PlanGeneration cap
Hobby3 generations / 24-hour rolling window
DeveloperUnlimited
Architect ProUnlimited

Hobby caps reset on a 24-hour rolling basis from the time of your first generation in the window. When the cap is reached, subsequent generation requests return HTTP 429 until the window resets. See plans and pricing for full feature comparison.

Best practices

  • Always respect Retry-After. Read the header value on every 429 and wait at least that many seconds before retrying. Ignoring it produces another 429 immediately and wastes a retry slot.
  • Apply exponential backoff with jitter. After the Retry-After window, add a small random delay (jitter) before each subsequent retry. This prevents synchronized retry storms when many clients hit the limit at the same time.
  • Use Idempotency-Key on repackage. Send a client-generated UUID in the Idempotency-Key header on POST /projects/:id/bundles/repackage requests. If the same key is received within 60 seconds, the server returns the original bundle ID without creating a duplicate or consuming an additional rate-limit slot. This lets you safely retry a repackage after a network failure without risking double-billing or duplicate bundles.
  • Cap total retries. Set a maximum retry count (typically 3–5) and surface a clear error to the user if all retries are exhausted. An open-ended retry loop can exhaust your per-minute window and delay recovery.

Backoff example

The following pseudocode shows the recommended pattern: read Retry-After, add jitter, and cap total attempts.

pseudocode
# Pseudocode — Retry-After-aware exponential backoff with jitter
attempt = 0
while attempt < MAX_RETRIES:
response = api.call(request)
if response.status != 429:
break
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
jitter = random.uniform(0, 0.3 * retry_after)
sleep(retry_after + jitter)
attempt += 1

The jitter term (random.uniform(0, 0.3 * retry_after)) spreads retries across a 30% window above the server-mandated delay, which is sufficient to break lock-step retry patterns under realistic load.

Next steps

With rate limits understood, continue with the full API reference or explore how the streaming protocol works during generation.