Documentation
The QUORUM API provides programmatic access to the full decision stack — behavioral analysis, fraud scoring, forensic case management, and institutional compliance filings. All endpoints require API key authentication and return structured JSON.
Authentication
Every request must include a bearer token in the Authorization header. API keys are issued per organization and scoped to a single tenant namespace. Keys do not expire but can be revoked at any time from the administrative console.
Key prefixes
| Prefix | Environment | Notes |
|---|---|---|
| qrm_live_ | Production | Generates real forensic cases and SAR filings |
| qrm_test_ | Sandbox | Full scoring, no regulatory reporting or case storage |
Requests authenticated with a qrm_test_ key follow identical decision logic but suppress all downstream regulatory actions (SAR/STR auto-filing, evidence package generation). Use sandbox keys during development and integration testing.
Browser SDK
The Quorum Browser SDK passively collects seven behavioral signal channels from authenticated user sessions and attaches them to every API call via request headers. Integration is a two-step process: include the script, then initialize with the current user's identifier.
Include
Initialize
Headers injected
| Header | Contents |
|---|---|
| X-Quorum-CIV-Signals | JSON-encoded 7-channel behavioral signal vector (Base64) |
| X-Quorum-Subject-Id | User identifier passed to init() |
Signal channels
| Channel | Metric |
|---|---|
| canvas_hash | Device rendering fingerprint via 2D canvas pixel hash |
| audio_entropy | AudioContext oscillator output distribution entropy (0.0–1.0) |
| webgl_hash | GPU renderer string + vendor hash via WebGL |
| hardware_profile | Logical CPU count, device memory, max touch points |
| typing_variance | Inter-keystroke interval variance from recent input events |
| mouse_entropy | Shannon entropy of recent pointer movement deltas |
| motion_variance | DeviceMotionEvent acceleration variance (mobile) or 0 (desktop) |
The SDK operates entirely passively after init(). It does not read DOM content, intercept form values, or make independent network requests. Signal collection runs in a background microtask; call sdk.destroy() on logout to clear the collection interval.
POST /api/v1/analyze
The primary decisioning endpoint. Submits a transaction or event for multi-tier fraud scoring. Returns a verdict with full reasoning, score decomposition, and active flags.
Request body
| Field | Type | Description | |
|---|---|---|---|
| organizationId | string | required | Your organization identifier |
| userId | string | required | Subject user identifier |
| transactionId | string | optional | External transaction reference |
| amount | number | optional | Transaction amount in base currency units |
| currency | string | optional | ISO 4217 currency code (default: USD) |
| merchantCategory | string | optional | MCC or free-form merchant category string |
| ipAddress | string | optional | IPv4 or IPv6 originating address |
| deviceFingerprint | string | optional | Client device identifier (SDK-generated or custom) |
| action | string | optional | Event type: payment, login, withdrawal, transfer, account_change |
| metadata | object | optional | Arbitrary key/value pairs passed through to forensic records |
Example request
POST /api/v1/analyze HTTP/1.1 Authorization: Bearer qrm_live_•••••••• Content-Type: application/json X-Quorum-Atomic-QID: 7f3a2b1c-... X-Quorum-CIV-Signals: eyJjYW52YXNfaGFzaCI6... X-Quorum-Subject-Id: usr_48f2a9e1 { "organizationId": "org_f84e21", "userId": "usr_48f2a9e1", "amount": 4750.00, "currency": "USD", "action": "payment", "ipAddress": "198.51.100.4", "merchantCategory": "ELECTRONICS", "deviceFingerprint": "dfp_9c3e..." }
Response Schema
All responses are JSON. A successful analysis returns HTTP 200 with the following structure.
{
"success": true,
"verdict": "FLAG",
"totalScore": 61,
"finalAction": "review",
"flags": [
"HIGH_VELOCITY",
"CROSS_BORDER_MISMATCH"
],
"reasoning": "Transaction velocity elevated (4 in 60min). IP geolocation (DE) inconsistent with account registration (CA).",
"scoreBreakdown": {
"velocityScore": 25,
"geolocationScore": 20,
"behavioralScore": 16,
"deviceScore": 0
},
"caseId": null,
"evidencePackagePath": null,
"processingMs": 43
}
| Field | Type | Description |
|---|---|---|
| verdict | string | PASS / FLAG / BLOCK |
| totalScore | integer | Composite risk score 0–100 |
| finalAction | string | allow / review / block |
| flags | string[] | Active risk flag codes (see Flag Reference) |
| reasoning | string | Human-readable decision rationale from the AI arbitration tier |
| scoreBreakdown | object | Per-signal-category score contributions |
| caseId | integer | null | Forensic case ID if a case was opened (BLOCK verdicts only) |
| evidencePackagePath | string | null | Path to generated evidence package (BLOCK verdicts only) |
| processingMs | integer | Total server processing time in milliseconds |
Verdict Codes
The decision engine maps total risk score to a three-tier verdict. Thresholds are configurable per organization; the defaults below apply to all accounts at provisioning.
| Verdict | Score Range | finalAction | Downstream |
|---|---|---|---|
| PASS | 0 – 34 | allow |
None. Session continues. |
| FLAG | 35 – 74 | review |
Event queued for analyst review. No automatic block. |
| BLOCK | 75 – 100 | block |
Session terminated. Forensic case opened. SAR/STR auto-filed if score ≥ 85. |
BLOCK verdicts at score ≥ 85 automatically trigger SAR filings under FinCEN Form 111 (US jurisdiction) and FINTRAC STR (Canadian jurisdiction) when SAR_AUTO_SUBMIT is enabled for the organization.
Flag Reference
Flags are human-readable identifiers for individual risk signals. A response may carry zero or more flags. Flags from multiple signal categories (behavioral, velocity, geographic, device) are combined into the total score.
Behavioral flags
| Flag | Score | Condition |
|---|---|---|
| NO_DEVICE_MOTION | +15 | DeviceMotionEvent variance = 0 on a claimed mobile device |
| AUDIO_CONTEXT_ANOMALY | +20 | AudioContext entropy < 0.1 (consistent with headless browser) |
| HIGH_TYPING_VARIANCE | +10 | Inter-keystroke interval variance > 2σ above session baseline |
| LOW_MOUSE_ENTROPY | +12 | Pointer movement entropy < 0.3 (scripted/automated movement pattern) |
| CIV_DRIFT | +25 | Continuous identity Z-score > 82 (session takeover indicator) |
| CIV_WARN | +10 | Continuous identity Z-score 55–81 (elevated drift) |
| CANVAS_MISMATCH | +18 | Canvas fingerprint changed within authenticated session |
Velocity flags
| Flag | Score | Condition |
|---|---|---|
| HIGH_VELOCITY | +25 | > 5 transactions in a 60-minute window |
| AMOUNT_THRESHOLD | +20 | Single transaction > $5,000 USD equivalent |
| RAPID_ESCALATION | +15 | Transaction amount 3× or more above 30-day average |
Geographic / network flags
| Flag | Score | Condition |
|---|---|---|
| CROSS_BORDER_MISMATCH | +20 | IP geolocation country differs from account registration country |
| TOR_EXIT_NODE | +35 | Source IP is a known Tor exit node |
| HIGH_RISK_ASN | +25 | Source IP belongs to a high-risk autonomous system (AbuseIPDB score > 75) |
| VPN_PROXY_DETECTED | +15 | IP reputation service reports VPN or datacenter hosting |
| IMPOSSIBLE_TRAVEL | +40 | Two events from geolocations that require faster-than-possible travel between them |
Device flags
| Flag | Score | Condition |
|---|---|---|
| NEW_DEVICE_HIGH_VALUE | +22 | First-seen device fingerprint + transaction > $1,000 |
| DEVICE_FINGERPRINT_ABSENT | +8 | No device fingerprint provided for an authenticated request |
| EMULATION_DETECTED | +30 | WebGL renderer or canvas output consistent with headless Chrome or Puppeteer |
Institutional API
Institutional-tier endpoints are scoped to /api/institutional/v1/ and require an Operational or Sovereign access tier. All institutional endpoints apply the Atomic Handshake protocol — each request must carry a valid X-Quorum-Atomic-QID header obtained from the handshake sequence below.
Atomic Handshake
The Atomic Handshake is a two-step challenge/response protocol that binds each institutional API call to a single-use quantum-inspired state token. Tokens expire after 30 seconds.
POST /api/v1/atomic/init Authorization: Bearer qrm_live_•••••••• → { "qid": "7f3a2b1c-...", "ttl": 30 }
GET /api/v1/atomic/verify/:qid Authorization: Bearer qrm_live_•••••••• → { "challenge": "a3f8..." } // Include challenge in subsequent request: X-Quorum-Atomic-QID: 7f3a2b1c-... X-Quorum-Atomic-Challenge: a3f8...
Key institutional endpoints
| Method | Path | Description |
|---|---|---|
| POST | /api/institutional/v1/analyze | Full deep analysis with AI arbitration and evidence packaging |
| GET | /api/institutional/v1/cases | List open forensic cases for the organization |
| GET | /api/institutional/v1/cases/:id | Retrieve a forensic case with full evidence manifest |
| POST | /api/institutional/v1/cases/:id/export | Generate a signed PDF evidence package for a case |
| GET | /api/institutional/v1/sar-filings | List SAR/STR filings for the organization with submission status |
| GET | /api/institutional/v1/audit-ledger | Access the cryptographic Merkle audit ledger (append-only) |
| POST | /api/institutional/v1/audit-ledger/verify | Submit a Merkle proof for record inclusion verification |
Error Codes
All errors return a structured JSON body with a machine-readable error code and a human-readable message.
{
"success": false,
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Retry after 12 seconds.",
"status": 429,
"retryAfter": 12
}
}
| HTTP Status | Code | Description |
|---|---|---|
| 400 | INVALID_REQUEST | Missing required fields or malformed JSON |
| 401 | UNAUTHORIZED | Missing or invalid bearer token |
| 403 | TENANT_MISMATCH | Organization ID does not match the authenticated API key's tenant |
| 403 | DECEPTION_SANDBOX | Request was identified as a scanner or probe; routed to isolated sandbox |
| 410 | STATE_COLLAPSED | Atomic handshake QID has expired or already been consumed |
| 429 | RATE_LIMIT_EXCEEDED | Request rate exceeded; Retry-After header included |
| 503 | ATOMIC_STATE_UNAVAILABLE | Redis state backend temporarily unavailable |
| 503 | CIRCUIT_OPEN | Downstream service circuit breaker is open; system in degraded mode |
Webhooks
QUORUM can POST event payloads to a configured HTTPS endpoint for real-time notification of significant decisions. Webhooks are configured per organization in the administrative console.
Signed delivery
Every webhook request includes an X-Quorum-Signature-256 header containing an HMAC-SHA256 signature of the raw request body, computed using your webhook secret. Verify the signature before processing the payload.
import crypto from 'node:crypto'; function verifyWebhook(payload, signature, secret) { const expected = crypto .createHmac('sha256', secret) .update(payload) .digest('hex'); return crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature.replace('sha256=', '')) ); }
Event types
| Event | Trigger |
|---|---|
| verdict.block | Any BLOCK verdict issued |
| verdict.flag | Any FLAG verdict issued |
| sar.filed | SAR/STR filing created (pending or submitted) |
| case.opened | New forensic case created |
| case.updated | Case status changed by analyst |
| civ.drift | Continuous identity Z-score exceeded block threshold during a live session |
Rate Limits
Rate limits are applied per API key (not per IP). Limits are enforced at the Redis layer and reset on a rolling window.
| Tier | Limit | Window |
|---|---|---|
| Analytical (default) | 300 requests | 15 minutes |
| Operational | 1,200 requests | 15 minutes |
| Sovereign | Unlimited | Contractual SLA applies |
When a rate limit is exceeded, the response includes a Retry-After header with the number of seconds until the window resets. Requests beyond the limit return HTTP 429 with code RATE_LIMIT_EXCEEDED.
Need higher limits or custom integration support?
Operational and Sovereign access tiers include dedicated integration engineering and custom SLA agreements.
Contact Institutional Sales