Service connections
A service connection is your org's registered handle for a sibling Quantum Elixir product (or any external HTTP service). It stores the base URL + an encrypted API key, and lets workflow nodes call sibling endpoints by slug rather than URL.
Why connect explicitly?
Three reasons:
- Encryption at rest. Storing the sibling API key in the workflow spec would expose it on every read of the workflow. Service connections store the key encrypted under AES-256-GCM with a per-org KEK; the workflow spec just references
service: "aml". - Health checks. The connection record tracks last-healthy timestamp; ops can see at a glance which sibling is unreachable.
- Catalog discovery. Once a service is connected, you get programmatic access to its endpoint catalog via
GET /api/catalog/services.
List connections
/api/service-connections{
"data": {
"connections": [
{
"id": "scn_01HXY...",
"serviceSlug": "identity",
"baseUrl": "https://identity.quantumelixir.tech",
"active": true,
"lastHealthyAt": "2026-05-24T08:14:22Z",
"createdAt": "...",
"lastUsedAt": "..."
}
]
}
}Register or upsert
/api/service-connections{
"serviceSlug": "aml",
"baseUrl": "https://aml.quantumelixir.tech",
"apiKey": "aml_a8f3c92e..."
}If a connection for that serviceSlug already exists, this upserts — updates baseUrl + apiKey atomically. Useful for rotation: rotate the sibling key in the sibling's dashboard, then upsert here.
Response (201):
{
"data": {
"connection": {
"id": "scn_01HXY...",
"serviceSlug": "aml",
"baseUrl": "...",
"active": true,
"apiKeyHash": "sha256:...",
"createdAt": "..."
}
}
}The API key is never returned again. To rotate, call upsert with the new value.
Allowed serviceSlug values
identityamlanti-frauddocument-intelligencebank-statementai-automation
For external (non-Quantum-Elixir) services, use custom:<your-slug>:
{
"serviceSlug": "custom:core-banking",
"baseUrl": "https://core-banking.bank-xyz.internal",
"apiKey": "your-internal-api-key"
}External services use the same apiKey shape as siblings — the key is sent as Authorization: Bearer <apiKey> on each outbound call. If your internal service expects a different scheme (Basic, custom header, mTLS), put a thin adapter in front of it that translates Bearer into your scheme — or open an issue and we'll prioritize a richer authScheme field. Workflow nodes referencing custom services work the same: service: "custom:core-banking".
Catalog discovery
/api/catalog/servicesReturns every connected sibling's endpoint catalog:
{
"data": {
"catalog": [
{
"slug": "identity",
"name": "Identity Platform",
"baseUrl": "https://identity.quantumelixir.tech",
"endpoints": [
{
"method": "POST",
"path": "/api/identity/document/ktp/capture",
"name": "KTP capture",
"inputSchema": { /* JSON Schema for body */ },
"outputSchema": { /* JSON Schema for response */ },
"scope": "verifications:view"
},
{
"method": "POST",
"path": "/api/identity/face/liveness",
...
}
]
}
]
}
}The dashboard's visual workflow builder reads this to surface auto-complete + schema validation when you wire up service_call nodes. Hand-written workflows can reference it for the same reason — your code can validate against the JSON Schemas to catch typos before publishing.
Health-check semantics
lastHealthyAt is updated every time:
- A workflow
service_callto this connection returns 2xx. - An explicit health-check request fires (background sweep every 60s).
If lastHealthyAt falls more than 5 minutes behind now, the connection is marked unhealthy: true in the response (dashboard shows a red dot). Workflows still attempt calls — health is informational, not gating.
To force a check:
POST /api/service-connections/{id}/testReturns { ok: true, latencyMs } or { ok: false, error }.
Rotating keys
Sibling product API keys should be rotated quarterly. Workflow:
- In the sibling product's dashboard, issue a new key with the same scopes.
POST /api/service-connectionswith the new key (upsert, same slug).- Wait for in-flight workflow steps to complete (use the workflow dashboard).
- Revoke the old key in the sibling's dashboard.
Because connections store the key encrypted-at-rest with a per-org KEK and never expose it again, you can't accidentally leak the key by reading the connection record back.
Never put a sibling API key in the workflow spec
Always use service: "<slug>" and let the connection provide the key. Putting apiKey: "..." directly in a service_call node is supported but strongly discouraged — the key ends up in plaintext in spec exports and audit-log payloads.
Audit
Connection mutations are immutable-logged:
- create
- upsert (with hash of old/new key for forensic compare without exposing values)
- delete
Export from the dashboard's audit log when due-diligence requires it.