Skip to content

Rate Limits

Requests are limited by two independent layers, and the tighter one wins:

  1. Per API key — the budget for the key you are using. Plan against this number.
  2. Per IP address — a coarser ceiling shared by every key behind the same network.

The IP layer exists to contain abuse. Unless you route a lot of traffic through one egress IP, the per-key figure is what will actually bind.

EndpointsLimit
GET /v1/products · GET /v1/balance · GET /v1/api-key · GET /v1/tasks/{token} · GET /v1/tasks/{token}/result · GET /v1/tasks/{token}/download60 requests / minute per API key (120 / minute per IP)
POST /v1/detect · POST /v1/detect/file10 requests / minute per API key (30 / minute per IP)
POST /v1/realtime/check/{series} · POST /v1/realtime/detectToken bucket — per API key: burst 60, refill 1/s (≈60 / minute sustained)
per account: burst 120, refill 2/s · IP layer: 180 / minute

Realtime is not a flat per-minute counter. It is a token bucket: you may spend a full burst of 60 tokens at once and then refill one token per second. Steady throughput is therefore about 60 checks / minute per key, while short spikes are absorbed by the bucket capacity.

Which headers you get depends on which layer answered, and the three groups do not behave identically:

HeaderMeaningWhen it is present
X-RateLimit-RemainingRequests (or tokens) left in the current windowEvery response on all three groups
X-RateLimit-LimitThe ceiling that was appliedEvery general and detection response, and every 429 from the IP layer. Never on a realtime response — realtime spends a bucket, so there is no fixed ceiling to report
Retry-AfterSeconds to wait before retryingOnly on a 429
X-RateLimit-ResetUnix timestamp when the window resetsOnly on a 429 from the general or detection group; never from realtime or the IP layer

X-RateLimit-Remaining is the one header you can rely on unconditionally, and the only one realtime reports on success.

Stop sending requests for the number of seconds given by Retry-After, then resume with exponential backoff. The response body tells you which layer you hit:

{ "message": "Too many requests. Limit: 60/min." }
LayerStatusBody
Per key — general429{"message":"Too many requests. Limit: 60/min."}
Per key — detection429{"message":"Too many detection requests. Limit: 10/min."}
Per key — realtime429{"code":"realtime_rate_limited","message":"Realtime detection rate limit exceeded.","retry_after":12}
Per IP429{"message":"Too many requests from this network."}

Only the realtime rejection carries a machine-readable code; the others are plain messages whose text states the limit that applied. Branch on the HTTP status and Retry-After, and read the message for diagnosis.