Skip to content

API reference

The control plane serves REST on :8080. Every /v1/ endpoint takes a Bearer token: a dashboard JWT or an API key.

The dashboard, CLI and SDKs all call this API. Use this page to call it with curl. The SDKs wrap the same endpoints in typed methods. This page covers the core resources; the full route list is in services/control-plane/cmd/server/main.go.

Pass your API key in the Authorization header on every request:

Authorization: Bearer hlx_live_your_api_key_here

Create keys under Settings > API Keys. Keys start with hlx_live_ and carry scopes (read, write, admin, or fine-grained ones such as agents:write and runs:execute). Scope enforcement is off by default; set LANTERN_AUTHZ_ENFORCE=1 and a key missing the required scope gets 403.

Sign-up, login, email verification, password reset, data export and workspace deletion (/auth/* and /v1/tenants/{id}) are documented on Accounts.

GET /v1/agents
Response: 200 OK — bare array
[
{
"name": "research-agent",
"currentVersionId": "v1",
"labels": {},
"createdAt": "2026-04-10T12:00:00Z"
}
]
GET /v1/agents/{name}
Response: 200 OK
{
"name": "research-agent",
"currentVersionId": "v1",
"manifest": {
"systemPrompt": "You are a research assistant...",
"model": "auto"
},
"labels": {},
"createdAt": "2026-04-10T12:00:00Z"
}
POST /v1/agents
Content-Type: application/json
{
"name": "my-agent",
"manifest": {
"systemPrompt": "You are a helpful assistant...",
"model": "auto"
}
}
Response: 201 Created
{ "name": "my-agent" }
DELETE /v1/agents/{name}
Response: 204 No Content
PATCH /v1/agents/{name} — update
POST /v1/runs
Content-Type: application/json
{
"agentName": "research-agent",
"input": { "topic": "quantum computing" }
}
Response: 201 Created
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"agentName": "research-agent",
"status": "queued",
"input": { "topic": "quantum computing" },
"createdAt": "2026-04-12T10:00:00Z"
}
GET /v1/runs/{id}
Response: 200 OK
{
"id": "550e8400-...",
"agentName": "research-agent",
"status": "succeeded",
"input": { "topic": "quantum computing" },
"output": { "summary": "..." },
"tokensIn": 820,
"tokensOut": 2100,
"costUsd": 0.0042,
"createdAt": "2026-04-12T10:00:00Z",
"updatedAt": "2026-04-12T10:00:08Z"
}

Run status values: queued, running, succeeded, failed, waiting, cancelled.

GET /v1/runs?limit=20&agentName=research-agent
Response: 200 OK — bare array
[
{ "id": "...", "agentName": "...", "status": "succeeded", ... }
]
GET /v1/runs/{id}/events
Accept: text/event-stream
Response: Server-Sent Events
The event name is the journal kind; data is JSON.
event: step_started
data: {"seq":1,"kind":"step_started","stepId":"plan","runId":"550e...","at":"2026-04-12T10:00:01Z","payload":{}}
event: step_completed
data: {"seq":2,"kind":"step_completed","stepId":"plan","runId":"550e...","at":"2026-04-12T10:00:03Z","payload":{"output":"..."}}
event: step_started
data: {"seq":3,"kind":"step_started","stepId":"search-0","runId":"550e...","at":"2026-04-12T10:00:03Z","payload":{}}
event: step_completed
data: {"seq":4,"kind":"step_completed","stepId":"search-0","runId":"550e...","at":"2026-04-12T10:00:06Z","payload":{"output":"..."}}
: heartbeat

Possible event kinds on a run stream:

  • step_started: a step began executing.
  • step_completed: a step finished with output.
  • step_failed: a step errored; payload has error.
  • step_retrying: transient failure, will retry.
  • step_waiting: waiting for human approval.
  • confidence_evaluated: confidence gate scored a step.
  • anomaly_detected: runtime anomaly reported by the harness.
POST /v1/runs/{id}/cancel — cancel a run
DELETE /v1/runs/{id} — delete a run
POST /v1/runs/{id}/receipt — issue a signed receipt
POST /v1/runs/{id}/feedback — score 1-5, optional comment
POST /v1/runs/forecast
Content-Type: application/json
{ "agentName": "research-agent", "input": { "topic": "..." } }
Response: 200 OK
{
"estimatedTokensIn": 800,
"estimatedTokensOut": 2000,
"estimatedCostUsd": 0.004,
"confidence": 0.82,
"wouldExceedBudget": false
}

Sessions are interactive multi-turn conversations. Send messages and stream the reply as it generates.

POST /v1/sessions
Content-Type: application/json
{ "agentName": "my-agent" }
Response: 201 Created
{ "id": "sess-uuid", "agentName": "my-agent", "status": "active", "createdAt": "..." }
POST /v1/sessions/{id}/messages
Content-Type: application/json
{ "content": "What is the capital of France?" }
Response: 200 OK
{ "turnId": "turn-uuid", "text": "Paris.", "tokensIn": 12, "tokensOut": 4, "costUsd": 0.00001 }
GET /v1/sessions/{id}/events
Accept: text/event-stream
event: message_delta
data: {"sessionId":"...","turnId":"...","seq":1,"delta":"Par"}
event: message_delta
data: {"sessionId":"...","turnId":"...","seq":2,"delta":"is."}
event: message_completed
data: {"turnId":"...","text":"Paris.","usage":{"tokensIn":12,"tokensOut":4,"costUsd":0.00001}}
A failed turn emits message_error.
GET /v1/sessions — list (bare array)
GET /v1/sessions/{id} — get
POST /v1/sessions/{id}/stop — stop a running session
DELETE /v1/sessions/{id} — delete session
POST /v1/connectors/install
Content-Type: application/json
{
"connectorId": "gmail",
"config": { "userEmail": "you@example.com" }
}
Response: 201 Created
{ "connectorId": "gmail", "status": "installed" }
GET /v1/connectors
Response: 200 OK — bare array
[
{ "connectorId": "gmail", "status": "installed", "installedAt": "..." }
]
POST /v1/connectors/{connectorId}/execute?action=send_email
Content-Type: application/json
{ "to": "friend@example.com", "subject": "Hello", "body": "..." }
Response: 200 OK
{ "result": { "messageId": "..." } }
POST /v1/connectors/{id}/test — test connection
DELETE /v1/connectors/{id} — uninstall

Schedules trigger agent runs on a cron expression. They are a separate resource from agents: one agent can have multiple schedules.

POST /v1/schedules
Content-Type: application/json
{
"agentName": "research-agent",
"cronExpr": "0 9 * * 1-5",
"timezone": "America/New_York",
"config": { "input": { "mode": "daily-digest" } },
"enabled": true
}
Response: 201 Created
{ "id": "sched-uuid", "agentName": "research-agent", "cronExpr": "0 9 * * 1-5", ... }
GET /v1/schedules — list (bare array)
PUT /v1/schedules/{id} — update
DELETE /v1/schedules/{id} — delete

Inbound webhook triggers start a run of one agent when GitHub, Sentry, PagerDuty or a signed generic sender posts to a public URL. Setup, signatures and status codes are on Webhook triggers.

POST /v1/agents/{name}/triggers — create {provider, secret?, inputTemplate?}; 201, secret shown once
GET /v1/agents/{name}/triggers — list (bare array, no secrets)
GET /v1/triggers/{id} — get
PATCH /v1/triggers/{id} — {enabled?, secret?, inputTemplate?}
DELETE /v1/triggers/{id} — 204
POST /v1/hooks/{id} — public receiver, authenticated by HMAC signature, not a token
POST /v1/settings/llm-providers
Content-Type: application/json
{ "provider": "anthropic", "apiKey": "sk-ant-..." }
Response: 200 OK
{ "provider": "anthropic", "configured": true }
GET /v1/settings/llm-providers — list configured providers (bare array)
POST /v1/settings/llm-providers/{provider}/test — test the key

Errors use a flat JSON body:

// Most errors
{ "error": "agent 'my-agent' not found" }
// Validation errors (may include field detail)
{ "error": "missing required field: agentName" }

Common HTTP status codes:

  • 400: bad request or validation failure.
  • 401: missing or invalid API key.
  • 403: insufficient scope or cross-tenant access.
  • 404: resource not found.
  • 402: budget exceeded (hard-fail policy).
  • 500: internal error.