Limits & quotas

Ingest rate limits, plan quotas, the dropped response marker, and payload size caps - and how the SDK handles each.

Ingest has two independent guards: a per-key rate limit that stops floods, and a plan quota that caps billable volume. They fail differently on purpose, and the SDK handles both automatically.

Per-key rate limit

Each API key may send at most 1,200 requests per minute to the ingest endpoint (a fixed window). A healthy browser client flushes at most ~12 requests/minute, so even a large site stays far under this - the limit exists to contain a leaked or abused key. Exceed it and ingest responds:

429 Too Many Requests
http
HTTP/1.1 429 Too Many Requests
Retry-After: 30

{ "error": "rate_limited" }

The SDK backs off exponentially and retries - events stay queued and send once the window clears, so nothing is lost to a brief spike.

Fails open

The rate counter is best-effort: if the check itself errors, ingest accepts the request rather than dropping data.

Plan quota & the dropped marker

Separately, every plan has a monthly events quota (events_count) with a 10% grace buffer. Only non-bot events count. When the quota (plus grace) is exhausted - or the account has no active plan - ingest deliberately does something different from the rate limit: it returns HTTP 200 with a dropped marker instead of an error.

200 OK - quota exhausted
json
{
  "ok": true,
  "inserted": 0,
  "snapshots": 0,
  "dropped": "quota_exceeded"
}

dropped is a stable marker telling the client the batch was intentionally not stored:

dropped valueTypeDescription
quota_exceededstringThe plan's monthly events quota (plus the 10% grace) is used up.
no_active_planstringThe account has no active plan, so events can't be billed or stored.

Why 200, not 429?

A 429 tells a client to retry - but an over-quota batch will never be accepted, so retrying would loop forever and drain the device. A 200 counts as delivered, so the SDK drops the batch and moves on - correct for a condition that only resolves when the plan resets or upgrades. The dropped field is there so your own tooling can tell the difference.

Payload & batch caps

Hard ceilings bound any single ingest request. The SDK stays well under them on its own; they exist to stop a runaway client or a decompression bomb.

LimitTypeDescription
Events per batch≤ 500More returns 413 batch_too_large.
Request body (compressed)≤ 2 MBLarger returns 413 payload_too_large.
Decompressed size≤ 12 MBUpper bound after gunzip; the SDK caps an uncompressed payload at ~900 KB.

Client-side throttling

Before anything reaches the network, the SDK throttles capture with a token bucket (a sustained rate with burst headroom), batches events, and gzips the payload. Ordinary apps never approach the server limits - these guards fire almost only on genuinely abnormal traffic.

Read limits don't apply here

This page is about ingest (writing events). The read surfaces - the REST API and MCP server - clamp result sizes with per-endpoint limit caps rather than a request-rate quota.