Developer Reference
API Reference
REST API for the Traffic Lights supervised autonomy platform. All routes are authenticated. All business routes are under /api/v1.
Every endpoint listed here is implemented and tested. Routes that are planned but not yet available are listed in Not yet available.
Base URL & environments
| Environment | Base URL | Use |
|---|---|---|
| qa | https://api.qa.traffic-lights.io | Integration testing, pilot validation |
| prod | https://api.traffic-lights.io | Production |
All requests use HTTPS. HTTP is not accepted.
Authentication
Every route is authenticated. Two methods are supported.
| Method | Header | Use |
|---|---|---|
| Bearer token | Authorization: Bearer <token> | Interactive or session-based callers. |
| API key | X-API-Key: <keyId>.<secret> | Machine callers. Secret returned once at mint time. |
Bearer wins. A route consults the API key only when no Authorization header is present. An empty Authorization header silently disables the key. Machine callers must send no Authorization header at all.
Example — API key
# Correct — no Authorization header
curl https://api.qa.traffic-lights.io/api/v1/processes \
-H "X-API-Key: kid_abc123.secret_xyz"
# Wrong — Authorization header disables the key
curl https://api.qa.traffic-lights.io/api/v1/processes \
-H "Authorization: " \
-H "X-API-Key: kid_abc123.secret_xyz"
API key scopes
A key carries one or more scopes. Scopes are exact strings — not hierarchical.
| Scope | Grants |
|---|---|
read | All read routes (GET). |
audit:write | The approval-history write route only. No read access. |
principal:resolve | POST /api/v1/principals/resolve only. No listing or search. |
ingest | Reserved — no endpoint accepts it yet. |
A key holding audit:write is refused by every read route. A key with an unrecognised scope returns 401 — indistinguishable from an invalid key.
Errors
| Status | Meaning |
|---|---|
401 | Missing, invalid, or insufficient credential. |
403 | Credential valid but scope insufficient for this route. |
404 | Resource not found or not visible to your tenant. |
422 | Validation failure. Returns a structured detail array — one entry per violated field with path, rejected value, and machine-readable error type. All violations reported, not just the first. |
5xx | Platform error. A first request to an idle service may take several seconds — retry once before treating as an error. |
422 example
{
"detail": [
{
"field": "tasks[0].execType",
"value": "INVALID",
"error": "invalid_enum_value",
"allowed": ["MACHINE", "HUMAN", "AGENT", "CORROBORATION", "NOOP"]
}
]
}
Health
Returns platform health. Use as a liveness check before integration tests.
# Response 200
{ "status": "ok" }
Processes
List process definitions for your tenant.
| Param | In | Type | Description |
|---|---|---|---|
| limit | query | int | Max results (default 25). |
| cursor | query | string | Pagination cursor from prior response. |
Create a process definition. Versioned on write — each write creates a new version effective from the write timestamp.
{
"name": "Invoice Reconciliation",
"description": "Nightly agent reconciliation with CFO sign-off gate",
"tasks": [
{
"taskId": "recon-agent",
"execType": "AGENT",
"label": "Agent reconciliation"
},
{
"taskId": "cfo-signoff",
"execType": "HUMAN",
"label": "CFO sign-off",
"deadlineSeconds": 86400
}
],
"flows": [
{
"from": "recon-agent",
"to": "cfo-signoff",
"condition": "detail.status == FAILED"
}
]
}
Run history for a process, newest first.
Current derived health (Red / Yellow / Green) and per-task state for the most recent run.
{
"processId": "proc-001",
"runId": "MEC-20260916T044343Z",
"health": "GREEN",
"tasks": [
{ "taskId": "recon-agent", "status": "SUCCESS" },
{ "taskId": "cfo-signoff", "status": "PENDING" }
]
}
Policies currently attached to a process, current version only.
Policies
Two policy types do nothing. delegate and branch policies are accepted, stored and returned, but nothing acts on them. Use retry, escalate, notify, and halt.
List all policy types available to your tenant.
Create a policy. Effective-dated on write. Changing a policy does not require a deployment.
{
"processId": "proc-001",
"taskId": "cfo-signoff",
"policyType": "escalate",
"config": {
"escalateTo": "coo@yourco.com",
"channel": "email",
"afterSeconds": 3600
}
}
Read a specific policy version.
Approvals
List pending approvals addressed to the authenticated caller. Returns approvals where the caller is the named assignee.
Role-holders who are not the named assignee may settle an approval that does not appear in their list. See Known limitations.
Read a specific approval with full context: what the agent or system proposed, downstream consequence, policy version in force, and current decision chain.
{
"approvalId": "apr-20260916-04721",
"runId": "MEC-20260916T044343Z",
"taskId": "cfo-signoff",
"assignee": "cfo@yourco.com",
"status": "PENDING",
"deadline": "2026-09-17T04:43:43Z",
"context": {
"agentOutput": "Variance of $4,210 on invoice #48291",
"confidence": 0.91,
"consequence": "Approval posts the reconciled entry"
},
"policyVersion": "INVOICE_AUTO v3",
"chain": []
}
Settle as approved. Run resumes and the next task dispatches. Decision is recorded with actor, timestamp, and policy version in force.
# Body optional
{ "note": "Reviewed source rows — variance within tolerance" }
Settle as rejected. Run does not continue past the rejected task. Decision and reason are recorded.
{ "reason": "Source invoice does not match. Routing to investigation." }
Pass authority to a named delegate. Hop is recorded in the decision chain. Approval is repointed to the delegate.
{
"delegateTo": "controller@yourco.com",
"note": "Delegating — out of office until Monday"
}
Delegation is unbounded. The permitted-hops value is displayed in the chain but not enforced. The platform does not refuse a delegation that exceeds it.
Approval history
Write an approval history record. Append-only. Requires audit:write scope.
Read the complete decision chain for a run — every decision, every hop, every actor, every timestamp.
{
"runId": "MEC-20260916T044343Z",
"chain": [
{
"actor": "cfo@yourco.com",
"kind": "Person",
"action": "APPROVED",
"at": "2026-09-16T06:14:22Z",
"policy": "INVOICE_AUTO v3",
"note": "Variance within tolerance"
}
]
}
Principal resolution
Given identifiers you already hold, returns display name, identity kind and delivery address for each.
# Request
{ "identifiers": ["cfo@yourco.com", "svc-account-001"] }
# Response
{
"resolved": [
{
"identifier": "cfo@yourco.com",
"kind": "Person",
"displayName":"Sarah Chen",
"email": "cfo@yourco.com"
},
{
"identifier": "svc-account-001",
"kind": "Service",
"displayName":"Reconciliation service"
}
]
}
Deliberately narrow. This route converts identifiers you already hold into delivery addresses. It cannot discover identifiers you do not have. Empty or wildcard requests are refused.
Event schema
Every participant communicates through the same event shape.
{
"source": "your-service-name",
"detail-type": "TASK_COMPLETE",
"detail": {
"runID": "MEC-20260916T044343Z", // most important field
"taskID": "recon-agent",
"status": "SUCCESS",
"severity": "INFO",
"message": "Reconciled 4,000 rows"
}
}
| Field | Level | Required | Description |
|---|---|---|---|
| source | envelope | yes | Where the event came from. |
| detail-type | envelope | yes | The event category. |
| runID | detail | yes | Correlation identifier, end to end. Ties every event, decision and record to one run. |
| taskID | detail | yes | Which task this event concerns. |
| status | detail | yes | STARTED | SUCCESS | FAILED |
| severity | detail | yes | ERROR | WARN | SUCCESS | INFO | DEBUG. Omitting defaults to INFO and may suppress notification delivery. |
| message | detail | no | Human-readable description. |
| timestamp | detail | no | Stamped automatically if omitted. |
Severity is not decoration. Notification delivery filters on severity. Always set it explicitly.
Flow conditions
A flow may carry a single comparison that gates whether its downstream task dispatches.
detail.status == FAILED
detail.status == SUCCESS
detail.severity == ERROR
| Operator | Meaning |
|---|---|
== | Equals |
!= | Not equals |
Conditions fail open. An unparseable condition is treated as true — the branch runs regardless. Keep conditions to a single comparison.
SDK quickstart
The Python SDK wraps event emission. It is a convenience layer over the HTTP API — not required.
# Install
pip install traffic-lights-events
# Configure
export TL_API_BASE_URL="https://api.traffic-lights.io"
export TL_API_KEY="<your API key>"
# Emit an event
from traffic_lights_events import emit_event
emit_event('sai.tl.billing', 'FLOW_CALLBACK', {
'runID': 'MEC-20260916T044343Z',
'taskID': '20006510',
'status': 'SUCCESS',
})
The SDK is optional. Any system that can make an HTTPS POST can emit events directly. Node: npm install @traffic-lights/events. Full guides: SDKs & REST API.
# HTTP — works from any language or stack
curl -X POST https://api.traffic-lights.io/api/v1/events \
-H "X-Api-Key: $TL_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"source":"sai.tl.billing","detail-type":"FLOW_CALLBACK","detail":{"runID":"MEC-20260916T044343Z","taskID":"20006510","status":"SUCCESS"}}'
No SDK required. Any stack, any cloud. If it can make an HTTPS POST, it connects to Traffic Lights.
Execution types
| Type | Value | Executed by |
|---|---|---|
| Machine | MACHINE | A system — DBT, Lambda, API call. Dispatched to an action; completion reported as an event. |
| Human sign-off | HUMAN | A person — run pauses, approver decides. |
| Agent proposal | AGENT | An AI agent — proposes an outcome, recorded as agent, subject to same policies as any outcome. |
| Corroboration | CORROBORATION | A checker — compares a claimed value against an independent record. Verdict branches the process. |
| No-op | NOOP | A marker step — records that a stage was reached without dispatching work. |
Roles
| Role | Permissions |
|---|---|
| Administrator | Author and modify process definitions, policies and users. Settle approvals. |
| Process owner | Settle approvals. Read everything in the tenant. |
| Approver | Settle approvals. Read everything in the tenant. |
| Viewer | Read only. |
Not yet available
| Capability | Notes |
|---|---|
| Event submission over REST | The ingest scope is reserved. No endpoint accepts it yet. |
| One-tap email approval | Approval notifications link into the app. Approving directly from email without signing in is not yet available. |
| Segregation of duties | The platform does not record who requested a run, so it cannot prevent self-approval. |
| Structured approval input | Approvers may approve, reject, or delegate. Capturing structured input alongside a decision is not yet available. |
| Outcome attachment | A defect or incident discovered after a run cannot yet be attached to that run's record. |
| Fan-in on the process graph | Two branches cannot converge on a shared downstream task. |
A claim you can check is a claim that must hold when you check it. Every item here is omitted from the API rather than documented as though it works.