Skip to main content

API Reference

Execute compliance simulations programmatically. All endpoints require an API key.

Authentication

Lumis uses Bearer token authentication. Generate an API key from Settings → API Keys. Keys are shown once at creation — store them securely.

Keys are stored as SHA-256 hashes. Lumis never retains the raw key value.

All requests
Authorization: Bearer lmk_live_••••••••••••••••••••••••
Treat your API key like a password. Rotate it immediately from the dashboard if it is ever exposed. Leaked keys can be deactivated under Settings → API Keys without affecting other keys in your workspace.
API keys require an active Pro trial or a paid Pro/Business plan. Keys are automatically paused when the trial expires and the workspace downgrades to Free. A paused request returns HTTP 402 with the header X-Lumis-Reason: trial_expired_keys_paused. Upgrade from the dashboard to restore access without regenerating keys.

Base URL

All API calls are routed to the Lumis edge environment via our standard REST endpoints.

The base REST URL for simulations is https://lumiscompliance.com/api/v1/simulate.

POST /api/v1/simulate

Run a compliance simulation. The payload is evaluated through the ruleset DAG and every node result is recorded in the audit trail.

Request body

NameTypeDescription
rulesetIdrequiredstringThe Convex document ID of the target ruleset (e.g. jx7abc123…)
payloadrequiredobjectArbitrary JSON object representing the transaction or entity to evaluate. Max 64 KB.
expected_outcome"pass" | "fail"Used for coverage analysis. Flags the simulation as matched or mismatched.
test_suitestringGroup related simulations together under a single test suite ID.
tagsstring[]Array of arbitrary string tags to annotate this simulation.
curl
curl -X POST https://lumiscompliance.com/api/v1/simulate \
  -H "Authorization: Bearer lmk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{
    "rulesetId": "jx7abc123",
    "payload": {
      "transaction_amount": 1500,
      "user_region": "US",
      "id_verified": true,
      "risk_score": 0.12
    }
  }'
TypeScript (fetch)
const response = await fetch("https://lumiscompliance.com/api/v1/simulate", {
  method: "POST",
  headers: {
    "Authorization": "Bearer lmk_live_••••••••",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    rulesetId: "jx7abc123",
    payload: {
      transaction_amount: 1500,
      user_region: "US",
      id_verified: true,
      risk_score: 0.12,
    }
  })
});
const result = await response.json();

Response

NameTypeDescription
transactionIdstringUnique ID of this simulation record in your audit log
status"passed" | "failed" | "error"Final verdict of the DAG evaluation
stepsExecutednumberNumber of DAG nodes that were evaluated
passedNodeIdsstring[]Array of node IDs that evaluated to passed
failedNodeIdstring | nullThe first node that caused a failure, or null on pass
auditTrailAuditEntry[]Ordered log of every node evaluation with timestamps
Success response (200)
{
  "transactionId": "tx_9p2kx8f",
  "status": "passed",
  "stepsExecuted": 6,
  "passedNodeIds": ["kyc_check", "sanctions", "aml_threshold", "risk_band", "id_verify", "terminal_pass"],
  "failedNodeId": null,
  "auditTrail": [
    { "nodeId": "kyc_check", "status": "passed", "timestamp": 1714000001234 },
    { "nodeId": "sanctions",  "status": "passed", "timestamp": 1714000001280 }
  ]
}

POST /api/v1/simulate/batch

Run up to 50 payloads against a single ruleset in one call. Recommended for high-volume automated testing and regression suites.

Request body

NameTypeDescription
rulesetIdrequiredstringThe Convex document ID of the target ruleset
payloadsrequiredobject[]Array of JSON objects to evaluate. Max 50 items.
testSuiteIdstringGroup this entire batch of simulations under a single test suite ID.
tagsstring[]Apply arbitrary string tags to every simulation in this batch.
TypeScript (fetch)
const response = await fetch("https://lumiscompliance.com/api/v1/simulate/batch", {
  method: "POST",
  headers: {
    "Authorization": "Bearer lmk_live_••••••••",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    rulesetId: "jx7abc123",
    payloads: [
      { transaction_amount: 200, user_region: "US" },
      { transaction_amount: 9800, user_region: "EU" }
    ]
  })
});
const result = await response.json();
// Returns: { success: true, data: { transactionIds: ["tx_1", "tx_2"] } }

Batch calls consume quota identically to individual calls. A 50-row batch uses 50 simulations from your monthly allowance.

Error codes

CodeMeaningResolution
UNAUTHORIZEDInvalid or inactive API keyRegenerate a key from Settings → API Keys
QUOTA_EXCEEDEDMonthly simulation limit reachedUpgrade your plan or wait for quota reset
NOT_FOUNDRuleset ID does not existVerify the rulesetId in your request
FORBIDDENRuleset belongs to another workspaceUse a rulesetId owned by your workspace
PAYLOAD_TOO_LARGEPayload exceeds 64 KBReduce payload size or split into multiple calls
API_KEYS_DISABLEDTrial expired or workspace on Free tierUpgrade to Pro — check X-Lumis-Reason: trial_expired_keys_paused header
USAGE_LIMIT_EXCEEDEDBusiness 100K cap reached, no pay-as-you-go sub activeEnable pay-as-you-go from Settings → Billing — check X-Lumis-Reason: usage_cap_exceeded header
RATE_LIMITEDToo many requests in a short windowBack off and retry — token bucket refills at 10 req/s

Rate limits

PlanMonthly simulationsBurst rate
Free10010 req / 10 s
Pro25,00010 req / 10 s
Business100,000 + MeteredCustom SLA

Exceeding the free or pro tier limits will result in a 402 Payment Required error. Business usage is metered nightly and invoiced at month-end.

Live Mode (BYOC Engine) API

The Live Mode (BYOC Engine) exposes two surfaces. Control-plane routes run on Lumis infrastructure and speak the same API-key/Bearer contract as the rest of this reference. In-container routes run inside your container on your hosts — live payloads never leave your network.

BaseURL for control-plane routes: the Lumis-hosted control-plane URL for your workspace, shown under Console → Settings → Live Mode. BaseURL for in-container routes: http://localhost:8080 (deployment-controlled).

In-container routes

GET /health

Response 200
{ "status": "ok", "version": "0.1.0" }

GET /pubkey

Returns the engine's Ed25519 public key. Evaluation seals can be verified against this key.

Response 200
{
  "algorithm": "Ed25519",
  "public_key": "8a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c"
}

POST /evaluate

Runs one payload through the cached ruleset bundle. The request body is kept in memory only — never logged or persisted.

The engine can serve multiple active rulesets from one container. Add a top-level ruleset_id string to the request body to select which ruleset runs; omitting it falls back to the workspace default (the most recently activated ruleset). The key is reserved and stripped before evaluation — it will never appear in your rule data or audit trail.
curl
curl -X POST http://localhost:8080/evaluate \
  -H "Authorization: Bearer lmk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "transaction_amount": 1500, "user_region": "US" }'
Success response (200)
{
  "final_status": "passed",
  "step_count": 3,
  "passed_node_ids": ["start", "pass"],
  "failed_node_id": null,
  "audit_trail": [
    { "node_id": "start", "action": "check", "result": "passed", "timestamp": 1714000001234 }
  ],
  "cryptographic_seal": "50577f3d718b5d060978854a30fef372e254970247d6d7d8023b05780f3218f861e0ce238a636bc11572bc58bbc429d860105f80b93a44b2c0ae8f5fc73a2d0c"
}

Errors: 403 { error: "license_revoked" } (license revoked), 503 { error: "no_ruleset_synced" } (no bundle yet), 404 { error: "unknown_ruleset" } (unrecognized ruleset_id), 404 { error: "multiple_rulesets_require_selector" } (no default and no selector), 400 { error: "…" } (evaluation error).

Control-plane routes

GET /api/v1/engine/sync

Called by the customer's engine to fetch every active ruleset bundle. Requires an active Pro/Business/Enterprise license. Each bundle's signature is an Ed25519 signature over its canonical bundle string; the engine rejects the whole response if any signature fails. default_ruleset_id points at the most recently activated ruleset, used as the fallback when a request does not specify one.

curl
curl -X GET "https://<your-control-plane-url>/api/v1/engine/sync" \
  -H "Authorization: Bearer lmk_live_••••••••"
Response 200
{
  "bundles": [
    {
      "workspace_id": "jf7abc123",
      "ruleset_id": "jx7abc123",
      "name": "AML Flood",
      "region": "US",
      "version": 3,
      "environment": "active",
      "starting_node_id": "start",
      "strictness": "medium",
      "required_fields": ["user.id", "amount"],
      "nodes": [
        { "id": "start", "node_type": "condition", "data": { "label": "Amount check", "field_to_check": "amount", "operator": "gte", "target_value": 10000, "mock_response": null, "audit_code": "AML-01" }, "on_pass": "pass", "on_fail": "fail" }
      ],
      "signature": "50577f3d718b5d060978854a30fef372e254970247d6d7d8023b05780f3218f8…"
    },
    {
      "workspace_id": "jf7abc123",
      "ruleset_id": "jx7def456",
      "name": "EU GDPR Live",
      "region": "EU",
      "version": 1,
      "environment": "active",
      "starting_node_id": "start",
      "strictness": "low",
      "required_fields": [],
      "nodes": [],
      "signature": "1a2b3c…"
    }
  ],
  "default_ruleset_id": "jx7abc123"
}

Errors: 401 { error: "license_not_active" } (Free tier or cancelled/expired subscription). With no active rulesets the response is 200 with "bundles": [] and "default_ruleset_id": null — the engine then clears its cache and /evaluate returns 503 no_ruleset_synced.

POST /api/v1/engine/heartbeat

Counts-only telemetry. The body carries just two numbers — no rule names, no payload fragments, no stack traces. The count is applied to your monthly simulation quota.

curl
curl -X POST "https://<your-control-plane-url>/api/v1/engine/heartbeat" \
  -H "Authorization: Bearer lmk_live_••••••••" \
  -H "Content-Type: application/json" \
  -d '{ "evaluations_count": 17, "period_seconds": 300 }'
Response 200
{ "ok": true }

evaluations_count must be an integer in [0, 1000000] and period_seconds in (0, 86400]. Violations return 400 { error: "invalid_telemetry" }. Non-active licenses return 401 { error: "license_not_active" }.

POST /api/v1/engine/export

POST /api/v1/engine/export

Flushes PII-safe evaluation seal records to the workspace's configured SIEM webhook. Enterprise only. Requires a Bearer engine API key. Each record contains the ruleset id/name/version, final status, step count, a sanitized per-node audit trail (node_id, audit_code, result — never payload values), and the Ed25519 cryptographic_seal.

Errors: 400 { error: "invalid_batch" } (oversized or malformed batch), 401 { error: "license_not_active" } (Free/Pro/Business or cancelled/expired).