Search the docs

Find a page or a section of one

Errors

Every error is the same shape:

json
{ "error": { "code": "TokenNotFound", "message": "Unknown or revoked secret API key" } }

Branch on code. The message is written for a human reading a log and may change; the code is the contract. A few validation errors from the agent's own endpoints (identification, the pulse, the credential lookup) also carry an issues array naming the fields that failed.

#Codes

The Server API, the assess family and the endpoints the agent and the mobile SDKs call:

CodeStatusMeansDo
TokenNotFound403The key is unknown, revoked, or the wrong kind for this endpoint — a management key sent to the Server API is unknown hereCheck you are sending a secret key to the Server API and the public key from the agent and the mobile SDKs. The Management API answers Unauthorized instead
CardNumberRefused400A card field held a card number (/assess, /assess/outcome)Send your processor's card fingerprint or a keyed hash of the number instead — see protecting checkout. The number is not echoed back.
KeyNotPermitted403The secret key was created for other uses — an assess-only key reading events or visitors, sayUse a key allowed to do this; an edge's key should stay assess-only
OriginNotAllowed403The request's origin is not in your allowed originsAdd it in Settings, or clear the list to allow every origin
DomainMismatch403The request arrived on a verified custom domain owned by a different organizationUse a key from the organization that owns the host
RequestFiltered403A request filter rejected an identificationExpected, if you configured it. Not billed, no event stored. (On /assess a filter is a block verdict, not an error.)
TrialEnded, TrialCallsUsed, SubscriptionEnded402An identification or assessment from an organization whose trial ended, whose trial calls are used, or whose subscription ended (billing)An owner subscribes on the dashboard's Billing page. Meanwhile the agent earns no receipt and the edge and server SDKs fail open: the site serves, unprotected
TooManyRequests429Rate limit exceeded — identification, challenges, the pulse, integrity reports, the waiting room, App Attest; and the Management API's expensive calls past their allowance (usage, fitting a model, reading calibration)Back off; Retry-After says how long
RateLimited429Too many breached-credential lookups from one address (60 a minute)Back off; this one sends no Retry-After
InvalidPayload400The body did not match the expected shape, or a field in it is unusable: an ip that is not an address, a phone not in E.164 form, a url that is not absolute, a PATCH that names nothing to change, a sealed payload that fails its checksRead the message, which names the field; for an identification, check the agent version
InvalidRequest400GET /related-visitors without visitor_idPass it
InvalidJson400The body was empty, not JSON, or nested more than 32 levels deep
PayloadTooLarge413The body was over the endpoint's limit: 1 MB for an identification and for the Management API; 256 KB for /assess, /assess/outcome and /assess/receipts; 512 KB for a browser's policy reports (/csp/{key}, which answers 204 whatever it holds); 64 KB for everything else. An identification is also held to 10,000 values (each array element and object member counts one)An identification is normally under 50 KB and some 600 values; look for something large in tag or a page field you added
EventNotFound404No such event in this key's environmentSee Reading a 404
VisitorNotFound404No such visitor in this key's environmentSee Reading a 404
TokenExpired401The session token sent to the pulse or the waiting room has expiredIdentify again for a fresh one (the agent drops the expired token for you)
TokenInvalid403The session token was rejected: malformed, a bad signature, or minted for another organization or environmentIdentify again; do not retry the same token
SessionRevoked403A revoked session tried to join a waiting roomExpected while the revocation lasts
QueueDenied403A session convicted as automation, or whose verdict was block, tried to join a waiting roomExpected. See waiting rooms
AddressRequired403A waiting room that binds admissions to the visitor's network (bindIp) was entered with no client address the server could seeSend the client's address the way your proxy setup says, or turn bindIp off
RoomNotFound404No waiting room with that slug in the key's environmentCheck the slug and the key's environment
TicketInvalid403A queue poll's ticket is not a queueToken this organization issuedSend the queueToken from the enter answer, not the ticket number
TicketGone410The spot in line has expired: abandoned for a day, an admission that lapsed, a revoked session, a closed roomEnter again
ChallengeInvalid400An App Attest registration's challenge is unknown, already used or expiredFetch a new challenge
AppIdsNotConfigured409App Attest registration in an environment with no Apple app idsSet appleAppIds with PATCH /environments/{id}
AttestationRejected400Apple's attestation failed verification, or its key id is not the one sentDo not trust the device's key

The Management API has codes of its own:

CodeStatusMeansDo
Unauthorized401No key, or not a live management key (a secret key is not one)Send a management key
Forbidden403The key lacks the scope (the message names it), tries to grant scopes it does not hold, or tries to act on an owner or an admin or to grant ownershipAdd the scope, or do it from the dashboard
BadRequest400A field failed validation; the body is not JSON, not an object, or nested more than 32 levels deep; a required ?environment= is missing; the body and ?environment= name different environmentsRead the message, which names the field
NotFound404No such record — or environment, for ?environment= — in this organization
Conflict409The change would break a rule: a name already taken, the plan's subdomain limit, the last owner, the default environment, a key revoking itself, or one more than an environment holds (20 webhooks, 10 log streams, 1,000 request filters) or an organization (50 environments, 200 keys not revoked, 20 proxy secrets, 10 encryption keys, 10 SCIM tokens)Read the message
SeatLimitReached409An invitation beyond the plan's seatsRemove a member or change plan
RuleLimitReached409A rule beyond the 500 an environment holdsDelete rules no longer needed (let-through rules that stopped matching among them)
ThreatFeedFull409Threat-feed entries beyond the 50,000 live ones an environment holdsDelete entries no longer needed, or add them with a ttlHours so they lapse
PayloadTooLarge413The body was over 1 MB
InternalError500Something failed on our sideRetry later

404 (EventNotFound, VisitorNotFound; NotFound on the Management API) is returned for a record that does not exist — or that belongs to another environment or organization. That is deliberate: any other answer confirms the record exists.

#Reading a 404

js
try {
  event = await antibot.getEvent(requestId)
} catch (e) {
  if (e.status === 404) {
    // Either it never existed, or this key cannot see it.
    // Most often: a staging key reading a production request id.
  }
}

If you are getting 404s for events you can see in the dashboard, check which environment your key belongs to.

#Sealed results

unsealEventResponse throws SealedResultError for a payload that is too short, has the wrong header, or cannot be opened by any supplied key — and when it is given no keys at all.

A wrong key and a tampered payload are not distinguished. Both mean do not trust this result, and saying which would tell an attacker whether they had guessed the key. Treat the throw as a denial, not a retry.

#Webhooks

Your endpoint's failures, not ours. Anything outside 2xx, or slower than three seconds, counts as a failure and is retried once after five minutes with the same event id. See Webhooks.

#Signals that are absent rather than false

Not an error, but the same class of mistake:

json
{ "result": false, "unavailable": true, "reason": "ipPseudonymized" }

unavailable: true means the signal could not be computed. Check it before you read result, or you will treat "no opinion" as "no detection". See Privacy.

#Agent errors

The browser agent throws if apiKey is missing. Network failures reject the promise from get(), and so does any error answer from the API (OriginNotAllowed, TooManyRequests, …), with the status and body in the message.

Identification failing should not take your page down:

js
let result = null
try {
  result = await agent.get({ ignoreCache: true })
} catch {
  // Decide what an unidentified visitor means for this action.
  // Usually: continue, and let the server treat it as unknown.
}

Whatever you do, do not fail open on the server side because the client did not send a request id. An absent identification is not a clean one.