Errors and status codes

All error responses are JSON with a short machine-readable code:

{ "error": "invalid_key" }

Some errors include extra fields (documented inline below, e.g. ca_gate_failed returns balance and minBalance). 429 responses always include a Retry-After header in seconds.

Full code table

Authentication / authorization

HTTPCodeMeaningWhat to do
401missing_keyNo Authorization: Bearer … header on the request.Add the header.
401invalid_keyKey prefix isn't ws_pub_ / ws_sec_, key doesn't exist, or key belongs to a different tracking page.Verify the key string and the tracking page ID in the URL match.
401revoked_keyKey has been revoked in the dashboard.Create a new key and swap it in.
403wrong_tierA secret-only endpoint was called with a public key. (No public endpoints emit this — included for completeness.)Use a secret key.
401missing_originPublic-key request with no Origin or Referer header.Ensure the browser sends Origin; for cURL, pass -H 'Origin: https://your-site.example'.
403origin_not_allowedOrigin was sent but isn't on the key's allowlist.Add the origin in the dashboard.

See Authentication for the full auth model.

Embedding flags

HTTPCodeMeaningWhat to do
403embed_disabledTracking page has isPublicEnabled or embedEnabled turned off.Enable both in the page's settings.
404not_foundTracking page doesn't exist (or its backing data couldn't be built).Check the ID.
404page_not_foundSame meaning, emitted only by POST /submissions during policy checks.Check the ID.

Submission payload validation

HTTPCodeMeaningWhat to do
400invalid_jsonRequest body wasn't valid JSON.Fix the body. Set Content-Type: application/json.
400missing_fieldsRequired fields missing or wrong type on POST /siws/nonce or POST /submissions.See the endpoint reference for required fields.
400missing_tracking_page_idGET /session/submissions was called without the trackingPageId query parameter.Add it.
400invalid_wallet_addresswalletAddress isn't a valid base58 Solana address.Use a real address.
400invalid_nickname_lengthNickname is empty or longer than 32 characters after normalization.Trim to 1–32 chars.
400invalid_nickname_charsNickname contains disallowed characters.Use only letters, numbers, spaces, and . _ -.

SIWS / nonce / signature

HTTPCodeMeaningWhat to do
400invalid_nonceNonce unknown, already consumed, or expired.Request a fresh nonce and retry.
400nonce_binding_mismatchNonce was issued for a different page, wallet, or API key.Make sure the same key mints the nonce and submits it, and the wallet/page match.
401invalid_signatureEd25519 signature didn't verify against the exact SIWS message returned by the nonce endpoint.Sign the message string verbatim (UTF-8 bytes). Don't reconstruct it.

Submissions policy / state

HTTPCodeMeaningWhat to do
409duplicateThis wallet already has a pending, approved, or auto_approved submission on this page.Don't resubmit. Use GET /session/submissions to inspect state.
422ca_gate_failedSubmitter's token balance is below the page's CA-gate minimum. Body: { error, balance, minBalance }.Acquire more of the gated token, or ask the owner to relax the policy.

Rate limits and cooldowns

All 429 responses include a Retry-After header in seconds. Honor it.

HTTPCodeMeaning
429rate_limit_keyPer-API-key rate limit exceeded.
429rate_limit_ipPer-IP rate limit exceeded.
429rate_limit_sessionSession-scoped limit (nonce issuance or submissions).
429cooldown_activeWallet on cooldown after a prior rejection.
429queue_fullPage has hit its pending-queue cap.

See Cooldowns and rate limits for the full model.

Internal

HTTPCodeMeaningWhat to do
500internalUnexpected server error.Retry with backoff. If persistent, report to the Wallet Sleuth team.

Endpoint → codes it can emit

EndpointCodes
GET /api/embed/tracking/{id}missing_key, invalid_key, revoked_key, missing_origin, origin_not_allowed, embed_disabled, not_found, rate_limit_key, rate_limit_ip
POST /api/embed/siws/nonceinvalid_json, missing_fields, invalid_wallet_address, plus all auth codes, plus rate_limit_key, rate_limit_ip, rate_limit_session
POST /api/embed/submissionsAll auth codes, invalid_json, missing_fields, invalid_wallet_address, invalid_nickname_length, invalid_nickname_chars, invalid_nonce, nonce_binding_mismatch, invalid_signature, embed_disabled, page_not_found, duplicate, ca_gate_failed, cooldown_active, queue_full, and all rate-limit codes
GET /api/embed/session/submissionsmissing_tracking_page_id, all auth codes, rate_limit_key, rate_limit_ip

Tips for robust error handling

  • Branch on error, not on status. Two endpoints can return the same status with different codes (e.g. 429 with rate_limit_key vs. cooldown_active), and the right recovery action differs.
  • Respect Retry-After strictly. The server returns the exact window remaining. Backing off less just burns another attempt.
  • Treat 5xx as transient. Retry with exponential backoff and jitter. Cap the retry count — some 500s indicate a bug worth reporting.
  • Don't swallow 401s. A previously-working key that starts returning invalid_key or revoked_key almost always means a key rotation or revocation. Page someone, don't just retry.
  • Reveal errors to your UI carefully. Codes like ca_gate_failed are user-actionable ("hold at least N tokens to submit"). Codes like nonce_binding_mismatch are developer-actionable; don't leak them to end users.

Related