Admaxxer Pixel API — Errors

Every API error response uses the same envelope. The HTTP status line indicates the class; the error.code string gives you a stable identifier you can branch on in client code.

Response Envelope

{
  "error": {
    "code": "insufficient_scope",
    "message": "This endpoint requires the 'pixel:write' scope",
    "details": { "required": "pixel:write", "available": ["pixel:read"] }
  },
  "meta": { "request_id": "req_abc123" }
}

Include the request_id in any support email — it lets us pull your exact request out of the server logs.

Error Codes

HTTPCodeMeaning & Fix
401missing_authorizationNo Authorization header. Add Authorization: Bearer YOUR_KEY.
401invalid_authorization_formatHeader was present but not in Bearer <key> form.
401invalid_api_keyKey does not match any stored hash. Check for trailing whitespace, env vars from the wrong environment, or a pasted hash vs raw key.
401api_key_revokedKey’s revoked_at is set. Create a new one.
401api_key_expiredKey’s expires_at has passed. Create a new one.
403insufficient_scopeKey exists but lacks the scope required for this route. details.required names the scope; add it and rotate.
400invalid_pipeThe pipe path segment was not in the allowlist. See Endpoints.
400invalid_visitorThe /visitors/{id} id was empty after trimming.
400invalid_bodyZod validation failed on POST body. details contains field-level errors.
429rate_limit_exceededCaller exceeded 60 req/minute. Respect the Retry-After header.
503ingest_unavailableanalytics ingest env var is missing on this server. Contact support.
503identify_unavailableIdentify ingest env var is missing. Contact support.
503analytics_errorDownstream analytics warehouse error. Retry after a short backoff.
500internal_errorUnhandled server error. The request_id is your best lead for support.

Retry Strategy

Common Troubleshooting

  1. “Works in dev, 401 in prod.” You deployed the dev key. Keys are environment-scoped because the hash table is different per database.
  2. “403 on every request.” The key exists but has no scopes. Recreate it with explicit scopes from Settings › API Keys.
  3. “JWT expired” from our analytics warehouse. Minted JWTs live for 120 seconds. Re-mint on every request instead of caching.
  4. “Empty data on a fresh website.” Not an error — the pipe returns an empty array until the first pageview. Fire a test event with POST /pixel/events.

Frequently asked questions

What does the error response envelope look like?

Every error response uses the same envelope: { "error": { "code", "message", "details" }, "meta": { "request_id" } }. The HTTP status indicates the class; error.code is the stable string you branch on; meta.request_id identifies the request in our server logs.

Which Admaxxer API errors should I retry?

Retry 429 rate_limit_exceeded after the Retry-After header with added jitter. Retry 500 internal_error and 503 codes with exponential backoff (1s, 2s, 4s, 8s, 16s) and give up after 5 attempts. Never retry any other 4xx — the request is wrong and a retry will not fix it.

Why am I seeing 401 invalid_api_key when the key looks correct?

Three common causes: trailing whitespace on the pasted key, environment-mismatched keys (dev key deployed to prod), or pasting the stored hash instead of the raw key value. API keys are environment-scoped because the hash table is different per database.

What does 403 insufficient_scope mean and how do I fix it?

The API key exists and authenticates but lacks the scope required for this endpoint. The details.required field names the scope (e.g., pixel:write). Open Settings › API Keys, create a new key with the additional scope explicitly checked, and rotate.

How do I make POST requests safe to retry?

Make them idempotent on your side: client-assigned event_id values, dedup tables on the receiving end, or upsert semantics. Admaxxer’s ingest pipeline tolerates duplicate event_id values within a 24-hour window, so a safe retry will not double-count.

A request failed — what do I include when I email support?

Include the meta.request_id from the failed response, the HTTP status, the error.code string, the timestamp (UTC), and a redacted copy of the request body. With request_id we can pull the exact request out of the server logs in seconds.

Related

Overview · Auth · Endpoints · Rate Limits