API reference
api.example.com/v1 as of May 2026. Auth uses a Cognito JWT Bearer token; workspace scope comes from the token, there is no X-Cendriix-Workspace header. Rate limits are enforced globally (intake: 5 req/min). Plan-tier tables are roadmap.The Cendriix REST API lets you trigger runs, query run state, manage agents and policies, and stream audit events, all from your own tooling.
Authentication
Authenticated requests use a Bearer JWT from Cognito (via POST /auth/login or the app). Workspace context is embedded in the token.
curl https://api.example.com/v1/runs \
-H "Authorization: Bearer <cognito-jwt>"API keys are created via POST /api-keys but middleware currently expects JWT auth in preview, check release notes before automating with keys alone.
Base URL and rate limits
All requests go to:
https://api.example.com/v1| Plan | Requests / minute | Requests / day |
|---|---|---|
| Starter | 60 | 5 000 |
| Growth | 300 | 100 000 |
| Enterprise | Unlimited | Unlimited |
Rate-limit state is returned in every response: X-RateLimit-Remaining andX-RateLimit-Reset (Unix seconds). HTTP 429 is returned when the limit is exceeded.
POST /runs
Trigger a new workflow run.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
workflow | string | Yes | Workflow slug (e.g. ship-from-ticket). |
ticket | string | No | Jira / Linear ticket key. |
env | string | No | preview, staging, or production. |
model | string | No | LLM override (e.g. claude-opus-4-5). |
dry_run | boolean | No | If true, plan without executing side effects. |
metadata | object | No | Arbitrary key-value pairs stored on the run. |
curl -X POST https://api.example.com/v1/runs \
-H "Authorization: Bearer <token>" \
-H "X-Cendriix-Workspace: acme-prod" \
-H "Content-Type: application/json" \
-d '{
"workflow": "ship-from-ticket",
"ticket": "JIRA-3421",
"env": "preview"
}'Response
{
"id": "run_a1b2c3d4",
"workflow": "ship-from-ticket",
"status": "queued",
"ticket": "JIRA-3421",
"env": "preview",
"created_at": "2026-05-19T09:00:00Z",
"cost_usd": 0
}GET /runs/:id
Retrieve the current state and cost of a run.
curl https://api.example.com/v1/runs/run_a1b2c3d4 \
-H "Authorization: Bearer <token>" \
-H "X-Cendriix-Workspace: acme-prod"Response
{
"id": "run_a1b2c3d4",
"workflow": "ship-from-ticket",
"status": "awaiting_approval",
"ticket": "JIRA-3421",
"env": "preview",
"preview_url": "https://preview-jira-3421.acme.cendriix.ai",
"cost_usd": 0.24,
"steps": [
{ "name": "orchestrator", "status": "done", "duration_ms": 11000 },
{ "name": "dev", "status": "done", "duration_ms": 161000 },
{ "name": "sre", "status": "done", "duration_ms": 72000 },
{ "name": "qa", "status": "done", "duration_ms": 45000 },
{ "name": "approval_gate","status": "awaiting", "duration_ms": null }
],
"created_at": "2026-05-19T09:00:00Z",
"updated_at": "2026-05-19T09:04:49Z"
}POST /runs/:id/approve
Approve a paused run at an approval gate.
| Field | Type | Description |
|---|---|---|
note | string | Optional human-readable note stored in the audit log. |
curl -X POST https://api.example.com/v1/runs/run_a1b2c3d4/approve \
-H "Authorization: Bearer <token>" \
-H "X-Cendriix-Workspace: acme-prod" \
-H "Content-Type: application/json" \
-d '{ "note": "Looks good, ship it." }'Response
{
"id": "run_a1b2c3d4",
"status": "running"
}POST /runs/:id/cancel
Cancel a queued or running run. Cancellation is immediate and non-reversible.
curl -X POST https://api.example.com/v1/runs/run_a1b2c3d4/cancel \
-H "Authorization: Bearer <token>" \
-H "X-Cendriix-Workspace: acme-prod"Response
{
"id": "run_a1b2c3d4",
"status": "cancelled"
}GET /agents
List all agents available in the workspace (built-in and custom).
curl https://api.example.com/v1/agents \
-H "Authorization: Bearer <token>" \
-H "X-Cendriix-Workspace: acme-prod"Response
{
"agents": [
{ "id": "agent_orchestrator", "name": "Orchestrator", "kind": "built-in", "model": "claude-sonnet-4-5" },
{ "id": "agent_dev", "name": "Dev", "kind": "built-in", "model": "claude-sonnet-4-5" },
{ "id": "agent_sre", "name": "SRE", "kind": "built-in", "model": "claude-sonnet-4-5" },
{ "id": "agent_qa", "name": "QA", "kind": "built-in", "model": "claude-haiku-4-5" },
{ "id": "agent_cus_f3a9", "name": "Legal review", "kind": "custom", "model": "claude-opus-4-5" }
]
}Security policy API
Manage guardrails via the security module (not POST /policies).
curl https://api.example.com/v1/security/policy \
-H "Authorization: Bearer <token>"GET /audit/logs
Query audit events. Supports cursor-based pagination.
Verify chain integrity with GET /audit/verify.
| Query param | Description |
|---|---|
since | ISO 8601 start timestamp (inclusive). |
until | ISO 8601 end timestamp. Defaults to now. |
actor | Filter by actor email or service account ID. |
event | Event type filter (e.g. run.approved). |
limit | Page size (max 200, default 50). |
cursor | Pagination cursor from previous response. |
curl "https://api.example.com/v1/audit/logs?since=2026-05-01&limit=50" \
-H "Authorization: Bearer <token>"Response
{
"events": [
{
"id": "evt_001",
"event": "run.approved",
"actor": "alice@acme.com",
"run_id": "run_a1b2c3d4",
"note": "Looks good.",
"timestamp": "2026-05-19T09:06:00Z"
}
],
"next_cursor": "eyJpZCI6ImV2dF8wMDEifQ"
}Errors
All errors use standard HTTP status codes and a consistent JSON body:
{
"error": {
"code": "run_not_found",
"message": "Run run_xxxxxxxx was not found in workspace acme-prod.",
"status": 404
}
}| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Malformed request body or missing required field. |
| 401 | unauthorized | Missing or invalid Bearer token. |
| 403 | forbidden | Token lacks the required permission scope. |
| 404 | not_found | Resource does not exist or is not visible to this token. |
| 409 | conflict | State conflict (e.g. approving a run that is not awaiting approval). |
| 429 | rate_limited | Rate limit exceeded. Retry after X-RateLimit-Reset. |
| 500 | internal_error | Unexpected server error. Contact support with the request ID. |
X-Request-Id header. Include this ID when contacting support, it lets us trace the exact request in our logs.