Prefer Swagger UI? Click hereThe same API in the classic OpenAPI explorer.
// reference · 6 min read

Limits and quotas

Every hard limit Ringside enforces, grouped by surface, with the exact byte counts, item counts, character caps and time windows the route code checks. These are validation ceilings. Hit one and you get a 400 invalid_request_error (or a 429 on the rate paths) with a stable code you can branch on. Account-level rate limits and wallet budgets are configurable per developer and per customer; the numbers on this page are the platform-wide hard caps that no configuration can raise.

How to read this page

Two kinds of limit exist in Ringside, and it helps to keep them apart. The first kind is a fixed validation ceiling baked into the request handler. An embeddings call may carry at most 2,048 inputs and a chat message body may serialize to at most 100,000 bytes. You cannot raise these. Exceed one and the request is rejected before any model is called, so you are not billed. The second kind is a configurable quota such as your developer rate limit, a customer rpm_limit or a monthly_budget_usd. Those are set per account and enforced at request time, and the rate ones return 429 with a Retry-After header. This page documents the fixed ceilings in full and points at the configurable ones.

Branch on code, never message

Every limit below maps to a stable error.code in the response body. Human-readable error.message strings change without notice. Match code (for example input_too_large, metadata_too_large, conversation_full) and you are forward-compatible. The request id is the X-Request-Id response header, not a body field.

Chat and message limits

The chat completions endpoint caps the serialized size of the messages you send and the number and size of multimodal content parts inside any one message. The byte cap is measured against the JSON-serialized messages array, so a few large base64 image data-URLs will hit it long before a wall of plain text would.

Chat request ceilings (src/lib/api/content-parts.ts).
LimitValueScopeError code on breach
Serialized messages100,000 bytesper POST /v1/chat/completions bodymessages_too_large
Image parts per message2per messagecontent_part_limit_exceeded
Image data-URL size20 MBper image part (decoded bytes)content_part_too_large
Audio data size25 MBper input_audio part (decoded bytes)content_part_too_large
Document (PDF) parts per message2per messagecontent_part_limit_exceeded
Document data-URL size20 MBper file part (decoded bytes)content_part_too_large

The image and document size checks decode the base64 payload of a data: URL and compare the byte length against the cap before the bytes ever leave the edge. An fc_file:<id> reference or a file_id is resolved server-side and the same 20 MB document cap applies to the fetched blob. Plain https:// URLs are passed through to the provider unmeasured. Only application/pdf is accepted for file parts today; any other mime returns 400 invalid_content_part.

Capability gating runs after size checks

A size or count breach takes precedence over a "model does not support this" error. If you send 3 images to a non-vision model, you get content_part_limit_exceeded first, not content_parts_unsupported_by_model. Fix the count, then the model choice surfaces.

File upload limits

Files uploaded through POST /v1/files (for batch input, vector-store ingestion or chat attachment) have their own ceiling that is much larger than the inline content-part caps. Use a file upload plus an fc_file: reference when an asset is bigger than the inline data-URL caps allow.

Upload caps. The 512 MB upload ceiling is independent of the smaller inline-part caps.
LimitValueNotes
File upload size512 MBper uploaded file, any purpose
Inline image (chat)20 MBdata-URL or resolved fc_file: blob, max 2/message
Inline audio (chat)25 MBbase64 input_audio part (decoded bytes)
Inline document (chat)20 MBPDF only, data-URL or resolved blob, max 2/message

Embeddings limits

The embeddings handler bounds both the array length and each string length before the upstream call, so one request cannot amplify cost or pressure the heap with an unbounded array or a multi-megabyte string. An empty input array is also rejected.

POST /v1/embeddings (src/lib/api/embeddings.ts).
LimitValueError code
Inputs per request2,048input_too_large
Characters per input string100,000input_too_large
Empty input arrayrejectedmissing_input
{
  "error": {
    "type": "invalid_request_error",
    "code": "input_too_large",
    "message": "Each 'input' item must be \u2264 100000 characters",
    "param": "input"
  }
}

Rerank limits

Rerank is the second pass of two-stage retrieval (vector search, then rerank). The document count and the query and per-document character lengths are all capped. A request is billed as one search unit, so the document cap is also a cost ceiling.

POST /v1/rerank (src/lib/api/rerank.ts).
LimitValueError code
Documents per request1,000too_many_documents
Query length10,000 charsquery_too_large
Per-document length100,000 charsdocument_too_large
Empty documents arrayrejectedmissing_documents

Vector store limits

Vector stores ingest files asynchronously and carry their own metadata. The file-batch limit bounds how many files one ingest call can attach; ingestion status moves through pending, in_progress, completed, failed or cancelled per file.

Vector-store ceilings.
LimitValueNotes
Files per file batch500per file-batch attach call
Store metadata4 KBserialized JSON; shares the 4 KB cap with customers and batches

Brains limits

Brains ceilings.
LimitValueError code / note
Entry body100 MBentry_too_large (413) on PUT /v1/brains/{id}/entries.
recall top_kdefault 8, max 100Clamped silently to the range.
recall misses_top_kdefault = top_k, max 100Bounds the explain_misses list. Clamped.
GET /entries limitdefault 100, max 500Offset pagination; has_more in the response.
GET /scopes / GET /entities limitdefault 100, max 500Required scope; offset pagination.
Idempotency window24 hA replayed idempotency-key with a different body → idempotency_key_reuse (409).

Brains endpoints are covered by the standard /v1 rate limits (the four enforcement layers on the rate-limiting page); there is no separate per-endpoint Brains limit today.

Conversation and thread limits

Conversations (conv_) and OpenAI-compatible threads (thread_) share a hard message cap. When a conversation reaches it, no new turn may start. A turn also takes a row-level lock so two concurrent turns cannot interleave on the same conversation; the lock self-expires so a crashed client never wedges a conversation permanently.

Conversation/thread ceilings (src/lib/api/conversation-lock.ts, metadata-validation.ts).
LimitValueBehaviour at limit
Messages per conversation/thread5,000lock acquire returns conversation_full; the conversation is sealed to new turns
Conversation lock TTL10 mina lock older than 10 min is treated as orphaned and may be re-acquired or swept
Conversation metadata2 KBmetadata_too_large (tighter than the 4 KB default because metadata is carried per row)
Only one active turn per conversation

Start a second turn while one is in flight and the lock acquire fails with already_locked (HTTP 409 conflict_error). The lock is released in a finally block on the holding request and, as a backstop, a sweeper reclaims any lock older than 10 minutes. So a hung turn frees its conversation within 10 minutes even if the holder never returns.

Batch limits

A batch references an input file uploaded with purpose=batch, targets one of three endpoints and runs in a fixed 24-hour window. The only valid completion_window value is "24h". Batches run at half the synchronous per-call price, but only above a small request floor so a one-line "batch" cannot claim the discount on otherwise-synchronous traffic.

POST /v1/batches (src/lib/api/batches.ts).
LimitValueError code / note
Requests per batch50,000enforced at worker validation
Batch metadata4 KBmetadata_too_large
Batch metadata keys16metadata_too_many_keys
Completion window"24h" onlyinvalid_completion_window on any other value
Discount floor10 requestsunder this, batch billing uses the normal 1.0x markup
Allowed endpoints3/v1/chat/completions, /v1/embeddings, /v1/moderations

Metadata object limits

Most Ringside resources (customers, vector stores, batches, conversations, assistants, threads) accept a free-form metadata object. The serialized size cap differs by surface, but the per-object key and value shape is uniform.

Metadata object shape and per-surface size caps.
ConstraintLimit
Keys per object16
Key length64 chars
Value length512 chars
Serialized size (customers, vector stores, batches)4 KB
Serialized size (conversations)2 KB

The size check runs Buffer.byteLength(JSON.stringify(metadata)) against the per-surface cap. The 2 KB conversation cap is deliberately tighter than the 4 KB default because conversation metadata is stored per row and a conversation can carry up to 5,000 messages.

Client token limits

Client tokens are short-lived, per-customer JWTs that a browser presents directly to /v1/* with the Authorization: Client <jwt> scheme. Your developer key mints them server-side via POST /v1/customers/{id}/client_tokens and must hold the api:client_tokens scope. Mint rate, token lifetime and the token's own per-minute rate are all bounded.

Client-token caps (src/lib/api/client-token-signer.ts, client-tokens.ts).
ParameterDefaultMinMaxOn breach
ttl (seconds)900603600invalid_ttl
rpm601600invalid_rpm_limit
Mint rate--100 / min per customer429 mint_rate_limit
origin_allowlist entry--512 chars eachinvalid_origin_allowlist

The token rpm is also clamped to the owning customer's rpm_limit: if you request rpm: 600 but the customer is capped at 120, the mint fails with rpm_exceeds_customer_cap. So the effective ceiling is the lower of 600 and the customer's own limit. Optional bind_ip pins the token to the minting client IP; origin_allowlist restricts which browser origins may use it. The token jti carries the ctok_ prefix.

curl https://api.fightclub.pro/v1/customers/cus_42/client_tokens \
  -H "Authorization: Bearer ko_<key>" \
  -H "Content-Type: application/json" \
  -d '{
    "ttl": 1800,
    "rpm": 120,
    "scope": ["chat", "conversations"],
    "origin_allowlist": ["https://app.example.com"]
  }'

Pagination limits

List endpoints are cursor-paginated. Pass limit to set the page size and after set to the previous response's next_cursor to page forward. The response shape is { "data": [...], "has_more": boolean, "next_cursor": string | null }; there is no object: "list" envelope field.

Pagination ceilings. A `limit` above the max is clamped down, not rejected.
List type`limit` default`limit` max
Most list endpoints20100
Vector-store queries50200

A limit outside [1, max] is clamped into range rather than erroring, so passing limit=500 on a standard list simply returns 100 rows. Some lists also accept before, status, order_by and external_id filters; see the per-endpoint reference for which apply.

Rate limits and budgets

Rate limiting is layered. Four enforcement points each hold their own counter and the lowest remaining wins: edge per-IP, then per-client-token, then per-developer, then per-customer. When any layer is exhausted the request returns 429 rate_limit_error with a Retry-After integer-seconds header and a retry_after_seconds field in the body. The response also carries X-RateLimit-Remaining for the current window. There is no X-RateLimit-Limit or X-RateLimit-Reset header.

Spend ceilings are separate from rate ceilings. A customer monthly_budget_usd over its limit returns 402 customer_budget_exceeded; an empty customer wallet returns 402 customer_wallet_empty; an empty developer API pool returns 402 wallet_empty. The per-customer rpm_limit and tpm_limit are the configurable rate quotas referenced by the client-token clamp above. Unlike the validation ceilings on this page, these are set per account and you raise them by changing the customer or developer record.

Lazy-create has its own rate

Attributing a call to an unknown customer auto-creates it, but auto-creation is rate-limited. Burst past it and you get 429 lazy_create_rate_exceeded. For bulk onboarding, create customers explicitly with POST /v1/customers instead of relying on lazy-create.

Quick reference

Every hard limit on one screen.
SurfaceLimitValue
Chatserialized messages100,000 bytes
Chatimage / document parts2 each per message, 20 MB each
Chataudio part25 MB
Filesupload size512 MB
Embeddingsinputs / chars per input2,048 / 100,000
Rerankdocs / query / per-doc1,000 / 10,000 / 100,000 chars
Vector storesfile batch / metadata500 files / 4 KB
Conversationsmessages / lock / metadata5,000 / 10 min / 2 KB
Batchrequests / metadata / window50,000 / 4 KB / 24h
Metadatakeys / key / value16 / 64 / 512 chars
Client tokensttl / rpm / mint60-3600s (900) / 60-600 (60) / 100/min
Paginationlimit default / max20 / 100 (vector queries 50 / 200)