Authentication and sessions
The three chat wires take the same credential. Durability is a separate choice: the OpenAI and Anthropic wires are stateless until you opt in, and AG-UI is durable from the first turn.
Authentication
The credential is a workspace API key, minted in Studio under
Settings → API keys and shown once when you create it. It looks like
sbk_live_<selector>_<secret>, and it carries the list of agents and workflows
it may call. See API keys for the format, the
permissions and how to revoke one.
All three chat wires expect that key as a bearer credential:
Authorization: Bearer <key> (the convention the OpenAI SDK sends) or
x-api-key: <key> (the Anthropic SDK's header) both work on any of them.
Authorization wins when a request carries both. A missing, unknown, revoked
or expired credential returns 401 with the matching wire's error shape
({"error": {...}} for OpenAI, {"type": "error", "error": {...}} for
Anthropic, {"type": "RUN_ERROR", "message": "..."} for AG-UI). One answer
covers all four cases, so a 401 never says which part of a guess was right.
A key the box accepts but that was not granted the agent you asked for returns
403 instead.
The two workflow routes a key opens, POST /api/workflows/<name>/start and
POST /api/workflows/<name>/chat, take the same key. The rest of the workflow
surface does not: it sits behind the container's own gate, which the control
plane and Stackbone Studio satisfy for you.
Under stackbone dev every gate is off, so a local box answers an
un-credentialed request on all of these. Keys are worth testing against a
deployed box, where they are actually checked.
Session keys
A plain chat call is stateless: you replay the full messages[] array each
turn, the same as calling OpenAI or Anthropic directly. The server keeps no
transcript and records each turn on its own, so a stateless conversation is
never grouped into a single session.
Two optional headers change that:
| Header | What it does | Where history lives |
|---|---|---|
x-stackbone-session |
Durable server-side session. The agent threads the conversation's history and tool state across calls, so you send only the newest user turn and the server carries the rest. Required for tool approvals. | On the server |
x-stackbone-conversation |
Grouping only. You still replay the full messages[], but the server joins the turns into one session so they show up together instead of as separate one-off runs. No durable state, no tool approvals. |
On the client (you replay it) |
Both take any non-empty string you choose, stable for the life of one
conversation. Send one, not both. A request carrying both counts as a durable
session, and the server ignores x-stackbone-conversation. With neither
header, each turn is an independent run and the server groups nothing.
AG-UI uses neither header. Its threadId field on the request body carries
the same durable, only-send-the-newest-turn semantics as
x-stackbone-session, and it is mandatory rather than opt-in. A non-empty
threadId is always a durable session. Leave it empty and you get one
stateless turn with no pause capability.