Overview
The Programmable Agent API exposes the same primitives the Standard Code CLI is built on. It is a small, predictable REST surface plus one WebSocket for live updates:
- Threads: conversations with an agent that have durable history and state. Create, list, read, and delete them.
- Messages: work sent into a thread and every response the agent produces.
- Streaming: live assistant text, tool activity, and end-of-turn signals delivered over a WebSocket.
- Thread state: a durable per-thread key/value store you can read and write.
Everything is JSON over HTTPS. Standard fetch and WebSocket calls provide the full API without an SDK.
Authentication
Every request is authenticated with your Standard Code API key as a bearer token:
Authorization: Bearer sak_live_…The fastest way to get a key is to sign in once with the CLI. On first run it opens your browser, and on approval it mints a personal key for your instance and stores it locally:
# installs the CLI and signs you in via the browser
npm install -g @standardagents/code
standardcode ~/some-project # press Enter for browser sign-inYour key is then written to ~/.standardagents/credentials under this instance's endpoint (the token field). Treat it like a password because it carries the same access as your session.
Quickstart
Use three calls to create a thread, send it a task, and read the reply:
# 1. Create a thread
curl -s https://api.standardcode.ai/api/threads \
-H "Authorization: Bearer $STANDARDCODE_KEY" \
-H "Content-Type: application/json" \
-d '{"agent_id":"standard_code_agent","tags":["api"]}'
# → {"threadId":"thr_abc123","agent_id":"standard_code_agent", ...}
# 2. Send a message to start the agent
curl -s https://api.standardcode.ai/api/threads/thr_abc123/messages \
-H "Authorization: Bearer $STANDARDCODE_KEY" \
-H "Content-Type: application/json" \
-d '{"role":"user","content":"Summarize what a durable object is in two sentences."}'
# 3. Read the conversation
curl -s "https://api.standardcode.ai/api/threads/thr_abc123/messages?limit=20" \
-H "Authorization: Bearer $STANDARDCODE_KEY"For live output, open the streaming WebSocket right after step 1 to watch the reply arrive as it is generated.
API reference
All paths are relative to https://api.standardcode.ai. Request and response bodies are JSON.
Threads
A thread is one conversation with an agent. It holds message history and durable state, and it can be resumed at any time from any machine.
Create a thread
| Field | Type | Description |
|---|---|---|
| agent_idrequired | string | The agent to run. Use standard_code_agent for the Standard Code coding agent. |
| tags | string[] | Labels for later filtering (e.g. group threads by project or job id). |
| initial_messages | object[] | Optional seed messages ({ role, content }). Omit to start empty and send the first message separately. |
// response
{ "threadId": "thr_abc123", "agent_id": "standard_code_agent" }List your threads
| Query | Type | Description |
|---|---|---|
| agent_id | string | Only threads for this agent. |
| limit | number | Page size (default 50). |
| offset | number | Pagination offset. |
| search | string | Match against thread titles / previews. |
Returns { "threads": [ { id, agent_id, title, tags, created_at, … } ] }, scoped to threads your key owns.
Get, update, or delete a thread
GET returns thread metadata. PATCH updates fields such as title or thread env (env_patch). DELETE removes the thread and its history.
Messages
Send a message
Sending a user message starts the agent's turn. The call returns as soon as the message is queued. The agent works asynchronously, and you can read the result by listing messages or using the stream.
| Field | Type | Description |
|---|---|---|
| contentrequired | string | The message text. |
| rolerequired | string | user, assistant, or system. Use user to give the agent work. |
| attachments | object[] | Files as { name, mimeType, data } where data is base64. Images become vision context. |
| silent | boolean | Store the message without showing it to the model. |
{ "role": "user", "content": "Add a health check endpoint and a test for it." }List messages
| Query | Type | Description |
|---|---|---|
| limit | number | Page size (default 100). |
| offset | number | Pagination offset. |
| order | string | asc or desc. |
| includeSilent | boolean | Include silent messages. |
Returns { "messages": [ { id, role, content, created_at, … } ] }. A queued message the agent hasn't processed yet is included with metadata.queued: true. An assistant message whose turn is finished has visible content and no pending tool calls.
Streaming (WebSocket)
Open a WebSocket to a thread to receive its output live. Because browsers and WebSocket clients can't set an Authorization header on the handshake, pass your key as the token query parameter:
wss://api.standardcode.ai/api/threads/thr_abc123/stream?token=$STANDARDCODE_KEYAdd &reasoning=1 to also receive the model's internal reasoning stream. The socket emits newline-free JSON text frames:
| type | Payload | Meaning |
|---|---|---|
| message_chunk | { chunk, message_id } | A fragment of the assistant's visible answer, as it's generated. |
| reasoning_chunk | { chunk, message_id } | A fragment of internal reasoning (only when you pass reasoning=1). |
| message_data | { data: { role, content, status, … } } | A complete message. An assistant message with text and no tool calls marks the end of a turn. |
| event | { eventType, data } | Lifecycle events like tool_call_started, tool_call_done, and generation. |
stream_ping periodically; the server replies stream_pong through its hibernation-safe auto-response path. Reconnect when no frame arrives within your silence window. Durable history preserves the output across socket connections.Thread state (KV)
Each thread has a durable key/value store. Use it to attach JSON-serializable metadata such as a job ID or status that resumes with the thread.
GET with no key browses all entries (supports search, limit, offset). POST writes { key, value }. DELETE removes a key.
Stopping a run
Interrupts the agent's current turn. The thread stays intact and can be continued by sending another message.
Full example
This plain Node example creates a thread, streams it live, and prints the answer without dependencies:
const BASE = "https://api.standardcode.ai";
const KEY = process.env.STANDARDCODE_KEY;
const auth = { "Authorization": `Bearer ${KEY}`, "Content-Type": "application/json" };
// 1. Create a thread
const { threadId } = await fetch(`${BASE}/api/threads`, {
method: "POST", headers: auth,
body: JSON.stringify({ agent_id: "standard_code_agent", tags: ["api"] }),
}).then(r => r.json());
// 2. Open the live stream
const ws = new WebSocket(`${BASE.replace("https","wss")}/api/threads/${threadId}/stream?token=${KEY}`);
ws.onmessage = (e) => {
const f = JSON.parse(e.data);
if (f.type === "message_chunk") process.stdout.write(f.chunk);
if (f.type === "message_data" && f.data?.role === "assistant" && !f.data.tool_calls) ws.close();
};
// 3. Give it work
await fetch(`${BASE}/api/threads/${threadId}/messages`, {
method: "POST", headers: auth,
body: JSON.stringify({ role: "user", content: "Explain what this API does in one paragraph." }),
});Limits & notes
- Ownership. A key only accesses threads it created. There is no cross-tenant access.
- Sessions are the unit. A thread actively working counts as one session against your plan, exactly like the CLI. Idle threads cost nothing; subagents are free.
- Host tools need the bridge. Tools that act on your machine (reading files, running commands) execute through the CLI's secure bridge. The API supports reasoning, planning, subagent orchestration, and answers. Connect the CLI to give the agent filesystem access.
- Logs are private. Instance admins retain exclusive access to raw model request and response logs. On a self-hosted enterprise license your organization is the instance admin, with full access to its own logs. See Standard Code for enterprise.
Write to enterprise@standardagents.ai with questions or requests for the API.