API
Your box (the container running your workspace, on your laptop under
stackbone devor deployed in your cloud) serves one HTTP API, and the runtime produces every route from the files you author. Any OpenAI, Anthropic or AG-UI client can chat with an agent. Any HTTP client can start a workflow. Studio and thestackboneCLI operate the box through the same server. You write no HTTP server, and no request routes through Stackbone: your caller talks to your box.
Everything the box serves, read live from the box itself: one agent and three workflows.
What the box serves
Four layers of HTTP, all on the same server and the same port:
| Layer | Routes | Who calls it |
|---|---|---|
| Agent chat | POST /openai/v1/chat/completions, POST /anthropic/v1/messages, POST /agui/v1/agents/:name, plus GET …/v1/models on the first two |
Your own product or service, with the OpenAI SDK, the Anthropic SDK, an AG-UI client, or curl. The Studio Playground is one such client. |
| Workflow runtime | POST /api/workflows/:name/start, POST /api/workflows/:name/chat, GET /api/workflows, GET /api/workflows/:name/schema, GET /api/discovery, the approval hooks |
Studio, stackbone workflows start, a timer the workflow declares, an inbound trigger, another workflow. Under stackbone dev, anything on your machine. |
| Health | GET /live, GET /health, GET /api/contract |
Your platform's probes, stackbone contract show, the control plane when it checks the box is reachable. |
| Operate | /api/runs, /api/sessions, /api/approvals, /api/logs, /api/events, /api/catalog, /api/prompts, /api/config, /api/secrets, /api/guardrails, /api/evals, and more |
Studio and the CLI. Every screen and every stackbone <group> verb is a client of these routes. See The surface area. |
Under stackbone dev the base URL is http://127.0.0.1:4242. A deployed box
listens on 8080, or on PORT when your platform sets one, and you reach it at
whatever address you gave it (see
Going to production). The
routes are the same in both.
Open that address in a browser under stackbone dev and the box prints its
own route list:
The box's own front page under stackbone dev: the routes, with the chat wires and the workflow start among them.
You never see a URL of the form stackbone.ai/…/your-agent. The control plane
holds your organization and the record of where each box lives. The traffic
goes to the box.
Chat with an agent from any client
An agent speaks three standard wire formats. A client built for OpenAI Chat
Completions, Anthropic Messages or AG-UI needs a base URL and a key and nothing
else: the official SDKs, LibreChat, Open WebUI, the Vercel AI SDK, LangChain,
curl. You pick the agent with the model field (OpenAI and Anthropic) or with
the :name in the URL (AG-UI). GET /openai/v1/models lists the agent names,
so a chat UI can fill its model picker from it.
curl http://127.0.0.1:4242/openai/v1/chat/completions \
-H 'Authorization: Bearer stackbone-dev' \
-H 'Content-Type: application/json' \
-d '{
"model": "my-workspace",
"messages": [{ "role": "user", "content": "In one sentence, what can you help me with?" }]
}'{
"id": "chatcmpl-1f390752-a191-40a3-9e72-2be0afe04faa",
"object": "chat.completion",
"model": "my-workspace",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "I can assist you with a wide range of tasks, including research, problem-solving, writing, and general inquiries.",
},
"finish_reason": "stop",
},
],
"usage": { "prompt_tokens": 6393, "completion_tokens": 24, "total_tokens": 6417 },
}Set "stream": true and you get the same server-sent events the vendor's own
API streams. A tool call arrives as tool_calls (OpenAI) or a tool_use block
(Anthropic). The Anthropic wire also carries the agent's thinking blocks;
AG-UI streams every reasoning block, tool call and tool result as its own event.
A turn is stateless unless you say otherwise. By default you replay the
full messages[] on every call, the same as calling the vendor directly, and
each turn is recorded as its own run. Send an x-stackbone-session header
with any stable string and the box keeps the conversation and its tool state on
its side, so you send only the newest turn. AG-UI's threadId does the same and
is always on. The
protocol reference covers
the second header, x-stackbone-conversation, which groups turns without
storing state.
A tool that needs a person pauses the turn. When an agent tool marked with
interruptOn fires, the turn stops and the decision lands in the Studio HITL
Inbox. The next call against that session answers 409 with
code: "approval_pending" until someone decides. Over AG-UI the pause is an
interrupt on the stream, and your client can resolve it in the next request
instead of going through Studio. See
Tool approvals.
Every turn, whoever sent it, is a run: it shows up under Runs in Studio
with the tools it called and the tokens it spent, and in
stackbone runs list.
Start and follow a workflow
A workflow is a 'use workflow' function under workflows/. The box gives
each one a start route, a detail and a schema, and Studio shows the route next
to the entry with a Copy curl button that produces the call below.
A workflow entry: its start route, its step, and the guardrail set wired to it.
curl -X POST http://127.0.0.1:4242/api/workflows/refund/start \
-H 'Content-Type: application/json' \
-d '{ "orderId": "ord_42", "amount": 19.99 }'{
"workflowName": "refund",
"status": "started",
"runId": "aa4f50bf-29df-58dd-86c1-5ddbbf8d74d2",
"worldRunId": "wrun_01M080NBDQD31ER017X2PV3241",
"trigger": "POST /api/workflows/refund/start",
}The call returns as soon as the run is enqueued. runId is the id you see in
Studio and pass to stackbone runs get. The run itself is durable: each
'use step' runs once, its result is written down, and a run that pauses for
hours (a sleep, an approval) resumes where it stopped after a restart.
The input is checked at the door. A workflow that declares an input schema gets it enforced before anything runs, and a bad payload starts no run:
{
"code": "workflow_input_invalid",
"message": "Input does not match the schema for workflow \"refund\".",
"issues": [{ "path": "amount", "message": "Invalid input: expected number, received undefined" }],
}| Situation | Status | code |
|---|---|---|
| No workflow by that name (the body lists the real ones) | 404 |
workflow_not_found |
| The input does not match the declared schema | 400 |
workflow_input_invalid |
| A guardrail refused the payload (the body names the rule) | 422 |
workflow_guardrail_blocked |
| The workflow failed to compile at boot | 503 |
workflow_compile_failed |
The same schema drives the Studio Playground. Pick a workflow and Studio builds
the input form from it, with the input and output contract beside it.
GET /api/workflows/:name/schema returns the two JSON Schemas, and
stackbone workflows schema <name> prints them.
The same schema the start route enforces, as a form.
Streaming workflows answer on /chat. A workflow written to hold a
conversation (its catalog mode is chat) is started with
POST /api/workflows/:name/chat and answers a server-sent-event stream of the
frames its steps write. See
Workflow agents.
A paused workflow resumes over a hook. A workflow that calls
requestApproval() parks until a decision is
posted to POST /api/workflows/hooks/:token/resume. You do not build that
round-trip: the HITL Inbox and stackbone hitl approve post it for you, and
the token is the only credential the route asks for.
Discovery routes, for a client that needs to know what is there before calling it:
| Route | Returns |
|---|---|
GET /api/workflows |
The workflow catalog: name, start route, whether it declares a schema, its steps. |
GET /api/workflows/:name |
One workflow's detail. |
GET /api/workflows/:name/schema |
Its input and output JSON Schema. |
GET /api/discovery |
The combined { agents, workflows } view of the workspace. |
GET /api/recurring-jobs |
Every timer armed on the box, when it fires next, and how its last execution went. |
The surface area
Studio and the CLI are HTTP clients of the box like any other. Every screen
and every stackbone <group> verb reads or writes through the box's own
routes, and the box enforces your role on each of them. The groups:
| Group | What you can do | Studio | CLI |
|---|---|---|---|
| Runs | List, filter and open runs; read the trace step by step; retry or cancel; stream one run's logs. | Runs | stackbone runs |
| Sessions | Group chat turns into conversations with a token total; open a turn's run. | Sessions | |
| Approvals | List what paused for a person, read the payload and the audit trail, approve or reject. | HITL Inbox | stackbone hitl |
| Logs | Tail everything the box prints, live, filtered by level, run or text. | Logs | stackbone logs tail |
| Catalog | Every agent and workflow the box serves, with model, tools, schema, guardrails and triggers. | Catalog | stackbone workflows list |
| Prompts | Read and edit the prompts your code loads by name; version and roll back. | Prompts | stackbone prompts |
| Dynamic config | Change values your code reads at runtime, without a redeploy. | Dynamic config | stackbone config |
| Secrets | Set, rotate and delete the keys your code reads. Values are written once and never listed. | Secrets | stackbone secrets |
| Guardrails | Rules the runtime enforces on a turn: block, mask, or hold for approval. | Guardrails | |
| Evals | Cases, suites and runs that score an agent or a workflow; the gate you put in CI. | Cases, Suites, Runs | stackbone eval <suite> |
| Recurring jobs | Every timer on the box, its next fire and last outcome. | Recurring jobs | |
| Storage, DB, RAG | Browse the box's object storage, query its Postgres read-only, manage RAG collections. | Storage, DB Explorer, RAG | stackbone storage, db, rag |
| Connections | Connect an outside service once, grant it, test it, and subscribe to its events as triggers. | Connections, Triggers | |
| Model provider | The credential and base URL the agents use to reach a model. Lives in the box, never in the control plane. | Model provider | |
| Events | One server-sent-event stream of run, step, session and approval lifecycle, so a screen updates without polling. | Every live screen |
Reach these through Studio and the CLI
The routes behind this table are the box's own. They are what Studio and the
stackbone CLI speak, and both ship in step with the box, but they are not
published as a contract for your own code to call yet. The three layers above
them (chat, workflows, health) are.
Who can call what
The box checks a credential on every request. Which one depends on the route:
| Routes | Credential |
|---|---|
Agent chat (/openai, /anthropic, /agui) |
A bearer credential: Authorization: Bearer <key> or x-api-key: <key>, whichever your SDK sends. A missing one answers 401 in the wire's own error shape. Today the box checks that a credential is present, not what it is: per-workspace API keys are not there yet, so keep a deployed box off the public internet or behind your own gateway until they ship. See Security and auth. |
| Workflow runtime and the operate routes | The five-minute identity token the control plane mints for your Studio session or your signed-in CLI, naming your organization, the box and your role. The box verifies it against the control plane's public keys and enforces the role per action (runs:read, hitl:decide, secrets:rotate, evals:run, …). The control plane itself signs its own calls to the box with the box's signing secret. |
Approval hooks (/api/workflows/hooks/:token/resume) |
The token in the URL. It is random and unguessable, and it is the capability. |
| Health and the handshake | None. /live, /health and /api/contract answer without a credential, so a probe never needs one. |
stackbone dev arms none of this. The local box holds no signing secret
and verifies no token, so every route answers, and the chat wires take any
non-empty bearer (stackbone-dev in the examples above). The tunnel it opens so
that Studio can reach it is a random address that disappears when the process
stops. Treat it as private while it lives.
Calls from a browser go through CORS. The box answers preflights for
https://app.stackbone.ai and any http://localhost:* origin by default. A
frontend of your own on another origin goes on the allowlist, in
stackbone.config.json under studio.corsOrigins or in the
STACKBONE_CORS_ALLOW_ORIGINS variable. See
Configuration.
Health, liveness and the handshake
The box splits "the process is up" from "everything it depends on works", so your platform does not recycle the container because one subsystem is slow:
| Route | Behaviour |
|---|---|
GET /live |
Instant 200 { "status": "ok" }. No probes. Point your platform's liveness check here. |
GET /health |
Runs every subsystem probe in parallel. 200 { "status": "ok", "checks": { … } }, or 503 { "status": "degraded", "checks": { … } } naming the subsystem that failed and why. checks covers what your workspace depends on, such as database and redis. |
GET /api/health |
The lighter answer stackbone dev serves instead of the two above. |
GET /api/contract |
The Stackbone Agent Protocol handshake: the protocol version the box speaks, the build it runs, and the capabilities your code can rely on (database.postgres_direct, storage.s3, queues.jobs, secrets.read_write, …). |
// GET /api/contract
{
"version": 15,
"minSupported": 1,
"capabilities": [
"database.postgres_direct",
"rag.basic",
"queues.jobs",
"secrets.read_write",
"config.read_write",
"approval.fire_and_forget",
"storage.s3",
"ai.openrouter",
"prompts.basic",
"browser.provider",
],
"build": { "name": "stackbone-cli", "version": "0.3.3" },
}stackbone contract show prints the same answer, and
stackbone contract validate checks your project against it before you build
an image. This handshake is what the SDK's ambient stackbone client
(stackbone.database, .storage, .secrets, …) reads to know what the box
offers; it is not one of the routes you drive yourself.
Read more
- Agent runtime protocol: the full contract, request and response shapes for all three chat wires, session headers, tool approvals over AG-UI, and the environment the runtime injects.
- Security and auth: how a caller proves itself to the box, and where every credential sits.
- Governance: the Studio screens that sit on top of the operate routes.
- Building workflows: declaring an input schema and triggering a run from code, a timer or an event.
- Agent-runtime CLI commands:
runs,hitl,logs,secrets,config,promptsandcontractfrom a terminal.