Authentication
Every Quantum Elixir API supports two authentication methods. You pick based on who's calling.
| Method | Used by | How |
|---|---|---|
| API key | Your backend, SDKs, scripts, cron | Authorization: Bearer qe_sk_... |
| Session cookie | Your team using our dashboard | Set via the dashboard login flow. Not for programmatic clients. |
This page covers API keys. Session cookies are documented on each product's dashboard.
Key format
qe_sk_<env>_<32-char-secret>env=sandboxorlive- Secret is base32. Compares case-sensitively.
The product-specific dashboards may show a slightly different prefix (e.g. qedi_ for Document Intelligence, bs_ for Bank Statement, aml_ for AML). The suite is migrating to a unified qe_sk_ prefix; existing keys keep working indefinitely.
Sending the key
Put it in the Authorization header:
curl https://sandbox.quantumelixir.tech/identity/api/auth/me \
-H "Authorization: Bearer $QE_API_KEY"Never put keys in query strings or URLs
We will reject any request that puts a Bearer token in a query parameter. URLs are logged everywhere — proxy logs, browser history, CDN caches.
Scopes
Every key is issued with an explicit list of scopes. A key without the right scope returns HTTP 403:
{ "error": "missing scope: customers:write" }The full scope vocabulary per product is documented on each product's overview page. The most common patterns:
| Scope | Grants |
|---|---|
read | Read-only across all resources (legacy wildcard) |
write | Read + write across all resources (legacy wildcard) |
{resource}:view | Read a specific resource type |
{resource}:write | Create/update a specific resource |
webhooks:manage | Register and rotate webhook endpoints |
api:manage | Issue, rotate, and revoke API keys |
Least-privilege by default
Production keys should never have write (the wildcard). Issue one key per integration concern: payments-service gets evaluate:write, kyc-service gets customers:write + verifications:view, etc. If one key leaks, you rotate just that one.
Rotation
Rotate any key at any time from Dashboard → Settings → API Keys → ⋯ → Rotate. Old key is valid for a 24-hour grace window so you can deploy the new key without downtime, then auto-revokes.
You can also rotate via API:
/api/api-keys/{id}/rotateThe response includes the new secret (shown once) and a previousValidUntil timestamp.
Acting as a user — actAsUserId
Machine accountability for four-eyes workflows. When an API key creates or transitions an artifact that is subject to four-eyes (rule approval, SAR submission, case close), AML and Anti-Fraud need to know which human is accountable for the action — an opaque key can't be the drafter or the submitter on its own.
Set actAsUserId on the API key to bind it to a real user account in your org:
/api/api-keys{
"name": "compliance-bot · MLRO",
"scopes": ["sar.write", "rule.read", "case.write"],
"actAsUserId": "usr_mlro_lead..."
}When the bot calls POST /api/sar-filings/{id}/submit, the server resolves the effective user to usr_mlro_lead... and writes both submittedById: "usr_mlro_lead..." and the key's apiKeyId into the audit log. Four-eyes enforcement compares effective submittedById against filedById — same as if a human had clicked the button.
| Property | Value |
|---|---|
| Required for four-eyes endpoints | Yes — request returns HTTP 422 api_key_not_bound_to_user |
| Required for read endpoints | No — read keys don't need a user binding |
| Editable post-creation | Yes — PATCH /api/api-keys/{id} with { "actAsUserId": "..." } |
| Visible in audit log | Always — both userId (effective) and apiKeyId are written |
Don't share keys across humans
Binding a key to a single human is the audit-trail contract. If two compliance officers share one bot key, four-eyes guarantees break — both become the same "user" from the system's view. Issue one key per officer + per task, or use dashboard logins.
Service principals (advanced)
When one Quantum Elixir product calls another (e.g. Orchestration calling AML on your behalf), it uses service principal keys. These are scoped to a specific calling service via callerServiceSlug. You don't issue these — Orchestration and AI Automation issue them automatically when you connect a sibling service.
Failure modes
| Status | Body | What it means |
|---|---|---|
| 401 | { "error": "missing or invalid Bearer" } | No key, malformed key, or revoked key |
| 401 | { "error": "key expired" } | Key passed its expiresAt |
| 403 | { "error": "missing scope: ..." } | Key is valid but lacks the scope this endpoint needs |
| 403 | { "error": "key is sandbox; endpoint is live" } | Cross-environment call (sandbox key against live URL) |
| 429 | { "error": "rate limit exceeded" } | Per-key rate limit — see Rate limits |
Webhook signatures
Webhooks use a different auth model — HMAC-SHA256 over the raw body. See Webhooks.