HTTP API
How-to: trigger runs and read results from anywhere, no VPC access needed.
toren dev serves the API (port 7433 by default; --api-port to change), with a pinned TOREN_API_TOKEN or an ephemeral one it mints and prints. On AWS the load balancer fronts it, terraform output api_url, token in Secrets Manager (api_token_secret_arn). The API covers every agent the deployment serves.
All endpoints except /healthz require Authorization: Bearer <token>, either the deployment's admin token (TOREN_API_TOKEN, created by the Terraform module) or an issued API key (below). Key management itself accepts only the admin token.
A machine-readable spec of this API lives at toren.run/openapi.json; point your generator or agent at it, then swap the server URL for your deployment's.
Discover what the deployment serves
curl -s "$API/agent" -H "Authorization: Bearer $TOKEN"Returns the deployment's sanitized structure, the discovery call to make before choosing agent/process for a run: { "agent": { "default": "...", "crews": { "<name>": { "name", "processes": [...], "defaultProcess"?, "agents": { "<ref>": { "model", "maxTokens", "maxSteps", "systemChars", "env": [names only], "tools": [{ "name", "description", "effects", "approval" }] } } } } } }. Env variable names only, never values; prompt sizes, never bodies.
Trigger a run
curl -s -X POST "$API/runs" \
-H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \
-d '{"input": "[\"solar shipping\",\"battery freight\"]"}'
# → 202 {"runId":"...","agent":"research_crew"}A deployment serves a fleet of process agents; "agent" in the body picks which one (omitted = the default). "process" picks a named process of that agent (omitted = its default_process, or main); the 202 echoes which one ran. Unknown agent or process names get a 400 listing what exists. GET /runs returns every agent's runs, each row labeled with its agent and process.
Check status, get the result
curl -s "$API/runs/$RUN_ID" -H "Authorization: Bearer $TOKEN"{
"status": "completed", // or running | waiting_approval | failed
"run": { "output": "…", "agent": "research_crew", "...": "..." },
"waves": [ { "name": "research", "tasks": 2, "settled": 2, "done": true } ],
"approvals": []
}Follow a run live with GET /runs/:id/events/stream (SSE): one data: frame per event as it lands, a done event when the run settles. The typed client wraps it as tailRun(runId, onEvent); the CLI as toren jobs tail.
GET /runs lists the newest 50 runs per crew; GET /runs/:id/events returns the full transcript, every recorded model call, tool call, and token count, straight from the event log.
Approve or deny a parked run
When status is waiting_approval, the approvals array carries the coordinates:
curl -s -X POST "$API/runs/$RUN_ID/approvals" \
-H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \
-d '{"taskId":"w1t0","stepId":"s4","granted":true,"comment":"ship it"}'The run wakes, executes the tool exactly once, and continues.
Manage API keys
Issue named, individually revocable keys instead of sharing the admin token:
curl -s -X POST "$API/keys" -H "Authorization: Bearer $ADMIN_TOKEN" \
-H "content-type: application/json" -d '{"name":"ci-pipeline"}'
# → { "key": { "id": "…", "name": "ci-pipeline", "prefix": "trn_ab12cd34", "secret": "trn_…" } }The secret appears in that response exactly once, only its SHA-256 hash is stored. GET /keys lists keys (never secrets); DELETE /keys/:id revokes immediately. Issued keys can trigger and inspect runs and resolve approvals, but cannot mint or revoke keys. The same operations exist on the CLI: toren keys create|list|revoke.
Schedules
Standing configuration, admin-token only (like /keys): GET /schedules, POST /schedules ({cron, input, agent?, process?, name?, tz?}), DELETE /schedules/:id, POST /schedules/:id/pause|resume. Firing semantics, exactly-once, crash-safe, catch-up on downtime, are in the scheduling guide.
Notes
- Responses are plain JSON; poll
GET /runs/:id, or stream live viaGET /runs/:id/events/stream(SSE). - On AWS the API is HTTPS out of the box (CloudFront fronts the stack,
terraform output api_url); custom domains are a two-CNAME exercise, see HTTPS & custom domains. - The API only calls the same core functions the CLI uses; durability semantics are identical however a run is triggered.