APIs
REST API
The control-plane API is how the console, your scripts, CI jobs, and the agent talk to Sirius. There is no /api or /v1 prefix. Paths look like GET /components and POST /workflows.
Local default: http://localhost:8080.
This page covers the contract: discovery, auth, tenancy, errors, and conventions. Then read:
- Resources — every domain and the routes you will call
- Identity — sessions, tokens, IdP, users, RBAC
- Operations — messages, logs, alerts, dashboard
- Advanced — codecs, BPMN, streams, migration, agent
- Recipes — end-to-end curl, Python, and JavaScript
- Studio API — the
/studio/*workbench
Discover the surface
The live catalog is the source of truth. It is generated from the runtime, so it does not drift from a hand-written list.
| Endpoint | Returns |
|---|---|
GET /openapi.json | OpenAPI 3.1 for every path |
GET /agent/tools | Each operation with method, path, permission, read_only, and an input schema |
GET /agent/mcp | The same catalog as a Model Context Protocol tools/list |
GET /health | Liveness and build (public) |
GET /ready | Fail-closed readiness — use this as a load-balancer gate |
GET /live | Process liveness for Kubernetes |
GET /metrics | Prometheus metrics (unauthenticated for scraping) |
curl -s "$SIRIUS/agent/tools?category=builder" \
| jq '.tools[] | {name, method, path, permission, read_only}'
Filter with ?category= (builder, studio, operate, …) or ?read_only=true.
Authenticate
Credentials are tried in a chain. Unrecognized schemes are skipped so session tokens, API tokens, and OIDC can coexist.
| Credential | How to send | Use |
|---|---|---|
| Session | Authorization: Bearer sess_… | Console sign-in; short-lived, refreshable |
| API token | Authorization: Bearer sk_… or X-API-Key: sk_… | Scripts, CI, services |
| OIDC JWT | Authorization: Bearer <jwt> | Production SSO |
| Break-glass | Deployment-configured emergency key | Incident access; audited |
ACCESS=$(curl -s -X POST "$SIRIUS/auth/login" \
-H 'content-type: application/json' \
-d '{"tenant_id":"default","username":"admin","password":"password"}' \
| jq -r .access_token)
curl -s "$SIRIUS/components?tenant_id=default" \
-H "Authorization: Bearer $ACCESS"
Login returns access_token, refresh_token, expires_at, subject_id, and tenant_id. Access tokens are short-lived (15 minutes by default). When one expires, POST /auth/refresh with the refresh token; both tokens rotate.
| Method | Path | Purpose |
|---|---|---|
POST | /auth/login | Exchange username and password (public) |
POST | /auth/refresh | Rotate the session pair (public) |
POST | /auth/logout | Revoke this session |
POST | /auth/logout-all | Revoke every session for the subject |
GET | /auth/sessions | List active sessions |
API tokens
Mint a long-lived, revocable bearer that authenticates as a principal with a fixed set of roles. The raw secret is shown once.
curl -s -X POST "$SIRIUS/api-tokens" \
-H "Authorization: Bearer $ACCESS" \
-H 'content-type: application/json' \
-d '{"tenant_id":"default","name":"CI pipeline","roles":["operator"],"expires_in_days":90}'
{ "secret": "sk_…", "token": { "id": "…", "roles": ["operator"], "revoked": false } }
| Method | Path | Permission |
|---|---|---|
GET | /api-tokens?tenant_id= | runtime:identity:read |
POST | /api-tokens | runtime:identity:write |
DELETE | /api-tokens/{id}?tenant_id= | runtime:identity:write |
Prefer tokens over interactive login for unattended jobs. See Issue an API token.
Public routes
These never require a credential: GET /health, GET /ready, GET /live, GET /metrics, POST /auth/login, POST /auth/refresh. Studio WebSockets (/studio/collab/ws, /studio/terminal/ws) use a one-time ticket minted over the authenticated API.
Local evaluation stacks may run without an authenticator. Production should not.
Tenancy
Every resource is tenant-scoped. The effective tenant is resolved in this order:
tenant_idin the body (writes) or query string (reads)- The authenticated subject’s tenant
- The
X-Sirius-Tenantheader
Cross-tenant access returns 404 not_found, not 403, so one tenant cannot probe another’s identifiers. * means account-wide scope and needs elevated permission.
Request and response conventions
- Bodies are JSON (
Content-Type: application/json). Binary routes useapplication/octet-stream. GETreads,POSTcreates or acts,PUTreplaces,PATCHpatches,DELETEremoves.- Timestamps are RFC 3339 UTC.
- IDs are stable strings. If you omit one, Sirius derives a slug from the name.
- List routes accept filters (
?state=,?tag=,?status=) and often?limit=.
Cursor paging
Three lists grow with traffic rather than configuration. They page with an opaque cursor and a server-side ceiling.
| Endpoint | Default / ceiling | Cursor location |
|---|---|---|
GET /audit | 100 / 1000 | X-Next-Cursor header |
GET /logs | 200 / 1000 | X-Next-Cursor header |
GET /bpmn/instances | 100 / 500 | next_cursor in the body |
Walk the list: first request without a cursor, then ?cursor= until the token is absent. A bad cursor is 400 — the server will not silently restart at the top. Paging is stable under writes: the cursor names the last row served, not an offset.
Idempotency
High-blast-radius mutations (supervisor actions, deployments, some replays) accept request_id or idempotency_key. Reuse the same key to retry. Do not issue a new key for the same intent.
Replays always create new history. They never rewrite the original record.
Errors
{ "error": { "code": "validation_error", "message": "name is required", "status": 400 } }
Branch on error.code, not the human message.
| HTTP | code (examples) | Meaning |
|---|---|---|
| 400 | invalid_json, validation_error, bad_request | Malformed or invalid request |
| 401 | invalid_credentials, authentication_required | Missing or invalid credential |
| 403 | forbidden | Authenticated but not allowed |
| 404 | not_found | Missing resource, or cross-tenant |
| 409 | conflict, duplicate_identifier | State conflict |
| 422 | (policy) | Semantically rejected (for example a failed promotion gate) |
| 429 | too_many_queries | Concurrent SQL console ceiling |
| 501 | not_configured | Capability not wired in this deployment |
| 503 | build_unavailable, unavailable | Dependency down |
Authorization
When RBAC is on, each route enforces a permission. Discover it on GET /agent/tools (permission field). A denied call is 403 forbidden.
Examples: POST /components needs runtime:component:write. POST /studio/workspaces/{id}/run needs studio:write — run is a write. POST /api-tokens needs runtime:identity:write.
Audit
Mutating calls are recorded. Attribute an agent or service with:
X-Sirius-Agent-ID—actor_type=agentplus the principal the agent acts asX-Sirius-Actor-Type—agent|service|humanX-Sirius-Actor-ID/X-Sirius-Actor-Email— operator attribution
Read the trail with GET /audit.
Retry guidance
- On
401with a session token, refresh once and replay. - On
429or503, back off. For writes, reuse the idempotency key. - Do not retry a write with a new key unless you intend a second action.