Skip to content
Documentation

API reference.

The gateway exposes a REST API over HTTP and a mirrored gRPC surface. All endpoints require authentication via API key or session token and enforce per-tenant isolation.

curl — submit a job
curl -X POST http://localhost:8081/api/v1/jobs \
  -H "X-API-Key: $CORDUM_API_KEY" \
  -H "X-Tenant-ID: default" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "job.hello.echo",
    "input": {"message": "Hello from the API"}
  }'
Base URL

https://api.cordum.io or your self-hosted gateway (:8081)

Auth Header

X-API-Key + X-Tenant-ID on every request

Rate Limit

Tenant/IP rate limiting is enabled; exceed limits returns HTTP 429.

Authentication

Every request must include an API key and tenant ID. Session tokens (from POST /api/v1/auth/login) are accepted via the same header or as a Bearer token. RBAC enforcement is enabled with CORDUM_REQUIRE_RBAC=true (enterprise).

OSS vs enterprise auth: OSS mode uses API key allowlists and tenant headers; enterprise auth provider adds multi-tenant API keys, advanced RBAC, and enterprise identity integrations.
curl — authenticated request
# API key authentication
curl -H "X-API-Key: cordum_xxxx..." \
     -H "X-Tenant-ID: default" \
     https://api.cordum.io/api/v1/jobs

# Session token (from /auth/login)
curl -H "Authorization: Bearer session-abc123..." \
     -H "X-Tenant-ID: default" \
     https://api.cordum.io/api/v1/workflows

API Key

Pass via X-API-Key header. OSS mode supports API key allowlists and single-tenant defaults.

RBAC Roles

admin — full access. user — standard. viewer — read-only (enterprise).

Tenant Isolation

X-Tenant-ID header on protected routes. Enterprise auth provider adds multi-tenant key/RBAC controls.

Auth & User Management
MethodPathDescriptionAuth
POST/api/v1/auth/loginLogin (user or API key)
POST/api/v1/auth/logoutInvalidate session
GET/api/v1/auth/sessionValidate current session
POST/api/v1/auth/passwordChange own password
GET/api/v1/auth/keysList API keysadmin
POST/api/v1/auth/keysCreate API keyadmin
DELETE/api/v1/auth/keys/{id}Revoke API keyadmin

Jobs

Jobs are the atomic unit of work. Submit a job, the Safety Kernel evaluates it, and the scheduler dispatches it to a worker pool. Supports idempotency via the Idempotency-Key header.

Output safety: GET /api/v1/jobs/{id} can include an output_safety object with decision, findings, and redacted/original pointers when output checks are enabled.
MethodPathDescriptionAuth
POST/api/v1/jobsSubmit a new job
GET/api/v1/jobsList jobs (cursor pagination)
GET/api/v1/jobs/{id}Get job details + safety decision
GET/api/v1/jobs/{id}/decisionsList safety decisions for a job
POST/api/v1/jobs/{id}/cancelCancel a running jobadmin
POST/api/v1/jobs/{id}/remediateRe-submit with remediationadmin
curl — submit a job
curl -X POST https://api.cordum.io/api/v1/jobs \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "topic": "job.inference",
    "capability": "gpt-4",
    "risk_tags": ["high-cost"],
    "context": {
      "prompt": "Summarize Q4 earnings report"
    }
  }'

# Response:
# { "job_id": "uuid", "trace_id": "uuid" }
curl — cancel a job (admin)
curl -X POST https://api.cordum.io/api/v1/jobs/{id}/cancel \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default"

# Response:
# { "id": "job-uuid", "state": "CANCELLED" }

Workflows

Workflows define DAGs of steps. Create a definition, then start runs against it. The dry-run endpoint previews policy decisions for every step without executing.

MethodPathDescriptionAuth
POST/api/v1/workflowsCreate or update a workflowadmin
GET/api/v1/workflowsList workflows
GET/api/v1/workflows/{id}Get workflow definition
DELETE/api/v1/workflows/{id}Delete a workflowadmin
POST/api/v1/workflows/{id}/runsStart a workflow runadmin
POST/api/v1/workflows/{id}/dry-runDry-run policy previewadmin
curl — start a workflow run
curl -X POST https://api.cordum.io/api/v1/workflows/deploy.pipeline/runs \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default" \
  -H "Content-Type: application/json" \
  -d '{ "context": { "env": "production", "tag": "v2.1.0" } }'

# Response:
# { "run_id": "run-uuid" }

# Dry-run (preview policy decisions, no side effects):
curl -X POST ".../workflows/deploy.pipeline/dry-run" \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default" \
  -H "Content-Type: application/json" \
  -d '{ "input": { "env": "production" } }'

Runs

Runs are instances of a workflow execution. Query step status, inspect the append-only timeline, or rerun from a specific step.

MethodPathDescriptionAuth
GET/api/v1/workflow-runsList all runs (cursor pagination)
GET/api/v1/workflow-runs/{id}Get run details with step status
GET/api/v1/workflow-runs/{id}/timelineGet append-only timeline
POST/api/v1/workflow-runs/{id}/rerunRerun from a specific stepadmin
POST/api/v1/workflows/{id}/runs/{run_id}/cancelCancel run + propagate to workersadmin
DELETE/api/v1/workflow-runs/{id}Delete a runadmin
curl — get run timeline
curl https://api.cordum.io/api/v1/workflow-runs/{id}/timeline?limit=200 \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default"

# Response:
# [
#   { "timestamp": "...", "event": "run_started", "step_id": "" },
#   { "timestamp": "...", "event": "step_dispatched", "step_id": "lint" },
#   { "timestamp": "...", "event": "step_completed", "step_id": "lint", "status": "SUCCEEDED" },
#   ...
# ]

Approvals

When the Safety Kernel returns REQUIRE_APPROVAL, the job is held until a human approves or rejects it. Approval is bound to the policy snapshot + job hash — if either changes, the approval is invalidated.

MethodPathDescriptionAuth
GET/api/v1/approvalsList pending approvals
POST/api/v1/approvals/{job_id}/approveApprove a held jobadmin
POST/api/v1/approvals/{job_id}/rejectReject a held jobadmin
curl — approve a pending job
curl -X POST https://api.cordum.io/api/v1/approvals/{job_id}/approve \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Approved by compliance team", "note": "Budget authorized" }'

# Response:
# { "job_id": "uuid", "trace_id": "uuid" }
# Job is re-published to the bus for processing.

Policy

Evaluate, simulate, and explain Safety Kernel decisions. Manage policy bundles, publish snapshots, and audit changes.

MethodPathDescriptionAuth
POST/api/v1/policy/evaluateEvaluate policy for a request
POST/api/v1/policy/simulateSimulate without state changes
POST/api/v1/policy/explainExplain matched rules + reasoning
GET/api/v1/policy/snapshotsList immutable policy snapshots
GET/api/v1/policy/rulesList active policy rules
GET/api/v1/policy/bundlesList policy bundles
PUT/api/v1/policy/bundles/{id}Update a policy bundleadmin
POST/api/v1/policy/publishPublish bundles (creates snapshot)admin
POST/api/v1/policy/rollbackRollback to previous snapshotadmin
GET/api/v1/policy/auditList policy change audit trail
curl — simulate a policy decision
curl -X POST https://api.cordum.io/api/v1/policy/simulate \
  -H "X-API-Key: cordum_xxxx..." \
  -H "X-Tenant-ID: default" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "job.k8s.deploy",
    "capability": "cluster.write",
    "risk_tags": ["prod", "destructive"],
    "actor_type": "service"
  }'

# Response:
# {
#   "decision": "REQUIRE_APPROVAL",
#   "reason": "Destructive prod operation",
#   "rule_id": "rule-456",
#   "constraints": { "max_runtime_ms": 300000 },
#   "remediations": [...]
# }

Dead Letter Queue

Every non-success terminal state creates a DLQ entry. Inspect failed jobs, retry them, or delete entries.

MethodPathDescriptionAuth
GET/api/v1/dlqList dead-letter entriesadmin
POST/api/v1/dlq/{job_id}/retryRetry a failed job from DLQadmin
DELETE/api/v1/dlq/{job_id}Delete a DLQ entryadmin

Config & Schemas

Configuration is scoped (system → org → team → workflow → step) and merged at evaluation time. Schemas validate workflow and step I/O.

Configuration
MethodPathDescriptionAuth
GET/api/v1/configGet config by scope
POST/api/v1/configSet config for a scopeadmin
GET/api/v1/config/effectiveGet merged effective config
Schemas
MethodPathDescriptionAuth
POST/api/v1/schemasRegister a JSON schemaadmin
GET/api/v1/schemasList registered schemas
GET/api/v1/schemas/{id}Get schema by ID
DELETE/api/v1/schemas/{id}Delete a schemaadmin

Packs

Install, verify, and manage packs — installable overlays that add workflows, schemas, config, and policy fragments.

MethodPathDescriptionAuth
GET/api/v1/packsList installed packs
GET/api/v1/packs/{id}Get pack details
POST/api/v1/packs/installInstall a packadmin
POST/api/v1/packs/{id}/verifyVerify pack integrityadmin
POST/api/v1/packs/{id}/uninstallUninstall a packadmin

Artifacts, Locks & Infrastructure

Upload/download artifacts, acquire distributed resource locks, list workers, and correlate jobs via traces.

MethodPathDescriptionAuth
GET/api/v1/artifacts/{ptr}Download an artifact
POST/api/v1/artifactsUpload an artifact
POST/api/v1/locks/acquireAcquire a resource lockadmin
POST/api/v1/locks/releaseRelease a resource lockadmin
GET/api/v1/workersList active workersadmin
GET/api/v1/traces/{id}Get correlated trace
GET/api/v1/statusGateway status + connectivity
GET/healthHealth check (no auth)

WebSocket Stream

Connect to /api/v1/stream for real-time bus events. Authentication is passed via the WebSocket subprotocol header. Events are newline-delimited JSON in CAP v2 BusPacket format.

Connection

  • URL: ws://gateway:8081/api/v1/stream
  • Subprotocol: cordum-api-key, <base64-key>
  • Query: ?tenant_id=default

Event Types

job_requestjob_resultjob_progressjob_cancelheartbeatsystem_alert

Events are filtered by tenant. Subscribes to sys.job.> and sys.audit.> NATS subjects.

WebSocket message (BusPacket)
{
  "trace_id": "abc-123",
  "sender_id": "scheduler",
  "created_at": "2025-03-15T10:00:05Z",
  "protocol_version": "2",
  "payload": {
    "job_result": {
      "job_id": "job-uuid",
      "status": "JOB_STATUS_SUCCEEDED",
      "output": { "summary": "Q4 revenue up 12%" }
    }
  }
}

MCP Endpoints

When MCP HTTP transport is enabled, the gateway exposes JSON-RPC routes for MCP clients over SSE + POST.

MethodPathDescriptionAuth
GET/mcp/sseOpen MCP SSE stream (HTTP mode)
POST/mcp/messageSend JSON-RPC request/notification
GET/mcp/statusGet MCP runtime status
MCP ping
curl -sS -X POST http://localhost:8081/mcp/message \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $CORDUM_API_KEY" \
  -H "X-Tenant-ID: default" \
  -d '{"jsonrpc":"2.0","id":1,"method":"ping"}'

Error Responses

All errors return a JSON envelope with an error field.

error response
HTTP/1.1 400 Bad Request
Content-Type: application/json

{ "error": "missing required field: topic" }
HTTP Status Codes
200Success
201Resource created
204Success, no body
400Invalid input or missing fields
401Missing or invalid credentials
403Insufficient role or tenant denied
404Resource not found
409Conflict (idempotency / concurrent edit)
413Payload too large (artifact limit)
429Rate limit or backpressure
500Internal server error
503Store unavailable (Redis / NATS)

Pagination

List endpoints use cursor-based pagination. Pass limit and cursor query parameters. Responses include a next_cursor field — when it is null, there are no more results.

pagination flow
# First page
GET /api/v1/jobs?limit=50

# Response
{ "items": [...], "next_cursor": 1707411599999999 }

# Next page
GET /api/v1/jobs?limit=50&cursor=1707411599999999

# Last page
{ "items": [...], "next_cursor": null }
Timestamp units: Jobs use microsecond timestamps. Workflow runs and DLQ use second timestamps. The gateway normalizes client input to the correct unit for each resource.

gRPC API

The gRPC surface mirrors REST on port :8080. Authenticate with the x-api-key metadata header. TLS is required in production.

proto
import "core/protocol/proto/v1/api.proto";

service CordumApi {
  rpc SubmitJob(JobRequest) returns (JobResponse);
  rpc GetJobStatus(GetJobStatusRequest) returns (JobStatusResponse);
}

// Authenticate via metadata:
// x-api-key: cordum_xxxx...