Skip to content
stage

REST API

Base path /api. JSON in and out (Content-Type: application/json). Field names camelCase. The TypeScript mirror lives in web/src/api/types.ts in the source repo.

The web app, the stage CLI and both MCP servers use this API. See Agents for the agent front ends.

PageCovers
Projectsproject mirror of T3 projects
Taskstasks, state mapping, link rules, handoff, predecessor base, session batch
Schedulesrecurring schedules and schedule rules
Threadshistory, search, transcript, pending questions, queued continuations
NotificationsWeb Push, notifications inbox, notification rules
Other endpointsimages, snippets, preferences, stats, agent interface

Conventions

  • Timestamps: ISO 8601 strings (UTC, e.g. "2026-11-08T10:00:00Z"). Nullable fields are null, never omitted.
  • IDs: app ids (id, projectId, taskId, afterTaskId, nextTaskId) are JSON numbers. T3 ids (t3ProjectId, t3ThreadId) are strings.
  • Lists are wrapped: { "projects": [...] }, { "tasks": [...] }, ...
  • PATCH bodies are partial: omitted fields are unchanged; null clears a nullable field.
  • Repeatable list query params accept repetition or commas: ?state=running&state=needs_input == ?state=running,needs_input.
  • from / to query params: ISO date (2026-11-01) or datetime. from inclusive, to exclusive. Filter on createdAt unless stated.
  • Errors: non-2xx responses have body { "error": string }. Some 409s add a machine-readable "code" (see Pending questions).
StatusMeaning
400invalid body or query (bad enum, missing required field, bad JSON)
404resource not found
409conflict: action not allowed in current state, duplicate unique value
502T3 call failed (T3 error message in error)
503T3 not connected (no valid token) or DB unavailable
500unexpected

Enums

NameValues
TaskStatebacklog launching running needs_input done settled failed interrupted cancelled (done: the run finished, not yet settled in T3; T3 calls this completed)
ThreadStatus (T3)idle preparing queued starting running waiting completed interrupted failed cancelled rolled_back
RuntimeModeapproval-required auto-accept-edits auto full-access (task default full-access)
InteractionModedefault plan (default default)
SendModeauto queue steer restart (default auto)
ProjectSourceapp (created via stage) t3 (imported from T3)
ThreadSourceapp (thread belongs to a task) t3 (any other thread)

Shared shapes

// ModelOption: T3 ProviderOptionSelection
{ "id": "effort", "value": "low" }          // value: string | boolean
 
// Workspace
{ "type": "root" }
{ "type": "worktree", "baseRef": "origin/main", "branch": "feat-x", "base": "ref" }   // branch: string | null (null = T3 picks)

Workspace maps to T3 workspaceStrategy: root → {type:"root"}; worktree → {type:"worktree", baseRef, branch?, startFromOrigin: baseRef has a "<remote>/" prefix} (remote = origin or upstream; feature/x is treated as local).

base (worktree only, always emitted; ref when omitted on input): ref starts from baseRef; predecessor starts a linked task's worktree from its predecessor's branch, with baseRef as the fallback (see Predecessor base). Invalid values, predecessor with root, and predecessor on a schedule are 400.

Health

GET /api/health

200 / 503:

{ "status": "ok", "db": "ok" }

T3 connection, sync, catalog

GET /api/t3/status

200 T3Status:

{
  "connected": true,
  "t3Url": "http://127.0.0.1:3773",
  "publicUrl": "http://t3.example.com:3773",
  "environmentId": "env_123",
  "clientId": "mcp_client_abc",
  "tokenExpiresAt": "2026-12-08T10:00:00Z",
  "adminTokenConfigured": true,
  "lastError": null,
  "lastFullSyncAt": "2026-11-08T10:00:00Z"
}

environmentId, clientId, tokenExpiresAt, lastError, lastFullSyncAt are nullable.

POST /api/t3/pair

Paste fallback: exchange a pairing code from t3 pair for a token.

Body: { "code": "ABCD-1234" }. 200 T3Status. 400 empty code. 502 pairing failed.

POST /api/sync

Run a full sync now (all T3 projects + threads into the mirror; creates app projects for new T3 projects; project title, root and archive state follow T3). Also reads top-level session details to populate normalized state and run metadata independently of legacy task state. Synchronous.

200 SyncResult:

{ "projects": 12, "threads": 776, "finishedAt": "2026-11-08T10:00:00Z" }

409 sync already running. 503 not connected. 502 T3 error.

GET /api/catalog

Cached orchestrator_capabilities (refreshed every 10 min). Only providers with no T3 constraints are listed.

200 Catalog:

{
  "providers": [
    {
      "providerInstanceId": "claude",
      "driverKind": "claude",
      "displayName": "Claude",
      "models": [
        {
          "id": "claude-haiku-5-5",
          "label": "Haiku 5.5",
          "options": [{ "id": "effort", "values": ["low", "medium", "high"], "default": "medium" }]
        }
      ],
      "runtimeModes": ["approval-required", "auto-accept-edits", "auto", "full-access"]
    }
  ],
  "fetchedAt": "2026-11-08T10:00:00Z"
}

displayName falls back to providerInstanceId; label falls back to id; options is [] when none; option default is nullable; runtimeModes is null when T3 does not report it. 503 not connected and no cache.