API access is not on sale yet.
The endpoint is live and these docs describe it accurately. Access belongs to the Pro plan, which we have not opened for purchase — so a key cannot be issued today, and these pages are here to be read rather than acted on. Free accounts have no API access, and requests from one are refused with a 403. Nothing here is a waiting list; there is simply nothing to join yet.
The error envelope
Errors come back as { "error": { "type", "message" } }:
{
"error": {
"type": "invalid_request_error",
"message": "`modality` must be one of: text, code, image, video"
}
}Status codes
| Status | Type | When |
|---|---|---|
400 | invalid_request_error | Malformed JSON or missing/invalid fields. |
401 | authentication_error | Missing or invalid bearer key. |
403 | permission_error | The key is valid but lacks the scope the endpoint requires. The message names the missing scope — detection needs detect:write. |
402 | quota_exceeded | The account has spent its monthly detection quota. The cap is measured per account, not per key, so minting a second key does not raise it. |
413 | invalid_request_error | The request is too large: text exceeds 200,000 characters, mediaRef exceeds 25 MB of decoded media, or the request body exceeds that plus a small envelope. An oversize body is refused from the Content-Length header before it is read. |
429 | rate_limit_error | Too many requests from this key. The limit is per key, per minute — 60 unless the key sets its own rate_limit_per_min. The response carries a Retry-After header in seconds. |
500 | api_error | Something broke on our side. Nothing is billed and no verdict is stored — retry, and if it persists, send us the response. |
503 | service_unavailable | The engine for that modality could not be reached. Image and video run on a separate hosted inference service, so this is what you get when that service is down or misconfigured — never a guessed verdict. |
Retries
429, 500 and 503 are the statuses worth retrying — everything else
describes something about the request that will not change on a second attempt.
On 429, wait for the number of seconds in the Retry-After header before
trying again. On 500 and 503, back off exponentially rather than retrying
immediately.