Troubleshooting
Problems organized by what you see, not by feature. Every error response carries a request_id; include it when you contact support. Branch your handling on error.type first and error.code when present (see the Error Reference).
Authentication
401 AUTH_UNAUTHENTICATED, or the browser SDK stops working after a few minutes
Likely cause: Participant tokens are short-lived (default 5 minutes, clamped to 1–60). The token expired and nothing re-minted it.
getToken callback to the SDK that fetches a fresh token from your server. The SDK caches it and calls your callback again on a 401. Do not try to extend token lifetime past 60 minutes; refresh instead. See Authentication.401 AUTH_API_KEY_INVALID
Likely cause: The API key is malformed, revoked, or from the wrong environment (test vs live).
bq_live_ or bq_test_ followed by 32 hex characters. “admin” is a scope, not a key prefix. Keys are server-only.403 AUTH_FORBIDDEN
Likely cause: The caller is authenticated but lacks the scope, or a participant token is touching another participant’s data. Minting participant tokens requires an admin-scoped key.
events:write, gamify:read, gamify:write, admin) and confirm the participant token’s subject matches the participant you are reading or writing.The browser SDK throws at construction when given an API key
Likely cause: You passed a server key (bq_live_ / bq_test_) to the browser client.
@bricqs/sdk-server and hand the browser only the participant token.Events & idempotency
Points or rewards granted twice
Likely cause: A request was retried without an idempotency key, so it was processed as two distinct events.
Idempotency-Key header on every write. A retry with the same key returns the original result with status: "duplicate" and the same event_id, and does not re-grant.IDEMPOTENCY_KEY_INVALID
Likely cause: The key is missing, too long, or uses disallowed characters. Allowed: [A-Za-z0-9_-:.], max 255.
purchase:order_123).IDEMPOTENCY_KEY_MISMATCH
Likely cause: The Idempotency-Key header and a body idempotency_key disagree.
An event succeeded but did not advance a challenge
Likely cause: Event-driven challenges must be global; engagement-scoped challenges do not advance from public API events.
Rate limits
429 with a RATE_LIMIT_* code
Likely cause: You crossed a per-IP, per-tenant, per-key, or per-participant limit.
Retry-After header first, then back off exponentially with jitter. Read the specific RATE_LIMIT_* code to know which limit you hit. Batching is not a bypass: batched events count individually. See Rate Limits & Quotas.Live updates
The UI stopped updating live and never recovered
Likely cause: The stream failed terminally (a 403, or retries exhausted). There is no automatic polling fallback.
onError by switching to periodic re-reads of the data hooks. See Live Updates.403 STREAM_PARTICIPANT_MISMATCH or STREAM_SCOPE_MISSING
Likely cause: The stream token is for a different participant than the path, or it lacks the read:state scope.
read:state (the mint default includes it). These are terminal — the stream will not retry them.Progression reads look a few seconds behind
Likely cause: General leaderboard reads are served from a cache and can be up to ~30s stale.
Things that will not happen (by design, today)
- Automatic points expiry does not run yet. Do not rely on it in launch-critical logic.
- Bricqs sends no participant notifications (email/push/in-app). Webhooks are the trigger; you send the message.
- There is no participant data export endpoint yet (erasure exists). Assemble access bundles yourself.
- Webhooks are not ordered and can be redacted on replay. Process idempotently and re-read on replay.
The full list is on Known Limitations & Guarantees.
