API reference
Errors
Every stable error code with its HTTP status, meaning and what to do about it.
All errors share one shape. Codes are stable; messages are safe to show to developers and end users but may be reworded.
Error body
{
"error": {
"code": "ORIGIN_UNAUTHORIZED",
"message": "This origin is not allowed for the site key."
}
}details is present for VALIDATION_FAILED (issues: [{ path, message }]) and some service errors. RATE_LIMITED responses from per-minute buckets include Retry-After: 60.
Codes
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
INVALID_REQUEST | 400 | The request is malformed. | Check the request shape against the reference. |
INVALID_JSON | 400 | The request body must be valid JSON. | Send a syntactically valid JSON body; empty bodies are treated as {}. |
UNSUPPORTED_MEDIA_TYPE | 415 | Send a JSON request body with Content-Type: application/json. | Set Content-Type: application/json. |
BODY_TOO_LARGE | 413 | The request body is too large. | Keep bodies under 32,000 bytes. |
NOT_FOUND | 404 | The requested resource does not exist. | Check the path and id; owned resources only. |
METHOD_NOT_ALLOWED | 405 | This method is not supported for this resource. | Use the method listed for the endpoint. |
AUTHENTICATION_REQUIRED | 401 | Sign in to continue. | Send Authorization: Bearer with a session token (or a reg_ token on /registration/keys). |
INVALID_SESSION | 401 | Your session is invalid or has expired. Sign in again. | Sign in again and use the fresh access token. |
FORBIDDEN | 403 | You do not have access to this resource. | The session may not access this resource. |
RATE_LIMITED | 429 | Too many requests. Try again shortly. | Wait for Retry-After seconds. On /verify after 10 attempts, request a new challenge. |
SITE_KEY_INVALID | 400 | The site key is not recognized. | Copy the site key from the dashboard; it starts with site_live_ or site_test_. |
SITE_DISABLED | 403 | This site is disabled. | Re-enable the site with PATCH /sites/:id {status:"active"}. |
ORIGIN_UNAUTHORIZED | 403 | This origin is not allowed for the site key. | Serve the page from https://<domain> or a subdomain, or add the origin to allowed_origins. |
ORIGIN_REQUIRED | 400 | An Origin header is required to create a challenge. | Include an Origin header (browsers do; server-to-server callers must add it). |
CHALLENGE_NOT_FOUND | 404 | The verification challenge does not exist. | Verify the ch_ id; challenges are not listable. |
CHALLENGE_EXPIRED | 410 | The verification challenge has expired. | Create a new challenge; raise ttl (max 300) if agents need more time. |
CHALLENGE_CONSUMED | 409 | The verification challenge has already been used. | The challenge already verified. Read GET /challenges/:id for the result, or create a new one. |
CHALLENGE_NOT_PENDING | 409 | The verification challenge is no longer pending. | The challenge was rejected. Create a new one. |
CHALLENGE_MISMATCH | 400 | The proof does not match the challenge. | Make challenge_id (or the Web Bot Auth nonce) match the challenge you fetched. |
AGENT_UNKNOWN | 404 | The agent is not registered. | Check agent_id; the agent may have been deleted. |
AGENT_DISABLED | 403 | The agent is disabled. | The owner must POST /agents/:id/enable. |
AGENT_REVOKED | 403 | The agent has been revoked. | Permanent. Create a new agent. |
KEY_UNKNOWN | 404 | The signing key is not registered for this agent. | The key_id does not belong to this agent. |
KEY_REVOKED | 403 | The signing key has been revoked. | Sign with an active key; rotate if needed. |
KEY_PENDING | 403 | The signing key has not completed registration. | Complete the registration challenge for this key first. |
KEY_INVALID | 400 | The public key is not a valid Ed25519 key. | Provide a 32-byte Ed25519 public key (raw base64url, SPKI, PEM or OKP JWK). |
KEY_LIMIT | 409 | This agent already has the maximum number of active keys. | Revoke an unused key; the maximum is five non-revoked keys per agent. |
SIGNATURE_INVALID | 400 | The signature could not be verified. | Rebuild the signature base exactly as documented and sign its UTF-8 bytes. |
SIGNATURE_MALFORMED | 400 | The signature is malformed. | Send all proof fields with the right types; signature must be base64url of 64 bytes. |
SIGNATURE_EXPIRED | 400 | The signature timestamp is outside the accepted window. | Sync the clock; created must be within 60 s of server time. |
SIGNATURE_AGENT_UNAVAILABLE | 502 | The Signature-Agent key directory could not be retrieved. | Make the key directory reachable over https without redirects and under 64 KiB. |
TEST_MODE_REQUIRED | 400 | Simulation is only available for test-mode challenges. | Simulation works only with site_test_ challenges. |
TOKEN_INVALID | 400 | The verification token is invalid. | Pass the exact token from the widget; do not modify or truncate it. |
TOKEN_EXPIRED | 400 | The verification token has expired. | Tokens live 10 minutes; verify promptly after the widget reports success. |
TOKEN_SITE_MISMATCH | 400 | The verification token was issued for a different site. | Verify with the site key that created the challenge. |
TOKEN_ALREADY_USED | 409 | The verification token has already been consumed. | Each token is single-use; treat a second presentation as replay. |
TOKEN_TEST_MODE | 400 | The token was issued in test mode. | Use a live site key, or pass allow_test: true outside production. |
REGISTRATION_TOKEN_INVALID | 401 | The registration token is invalid, expired or already used. | Mint a new registration token; they expire after 15 minutes and are single use. |
VALIDATION_FAILED | 422 | Some fields are invalid. | Read details.issues for the failing fields. |
CONFLICT | 409 | The request conflicts with the current state. | See the message: duplicate key, or an account limit reached. |
SERVICE_UNAVAILABLE | 503 | The verification service is temporarily unavailable. | Retry with backoff; check /api/v1/health. |
INTERNAL_ERROR | 500 | Something went wrong on our side. | Retry; include X-Request-Id when reporting. |
Client-side codes
The SDKs, the CLI and the widget raise a few codes of their own before a request reaches the API. They never appear in an HTTP response body.
| Code | Raised by | Meaning |
|---|---|---|
NETWORK_ERROR | @imnotahuman/agent, @imnotahuman/server | The API could not be reached. |
REQUEST_FAILED | @imnotahuman/agent, @imnotahuman/server, website | The response was not JSON or carried no error code. |
INVALID_RESPONSE | website | The response body could not be parsed. |
INVALID_PRIVATE_KEY | @imnotahuman/agent | The private key is not a 32-byte Ed25519 seed or PKCS#8 PEM. |
INVALID_CHALLENGE | @imnotahuman/agent, CLI | The argument is neither a ch_ id nor a challenge URL. |
NOT_REGISTERED | @imnotahuman/agent, CLI | No agent id / key id yet; run init or register first. |
WIDGET_LOAD_FAILED | @imnotahuman/react | widget.js did not load or initialise. |