Using the API
The interactive API Reference is generated from the OpenAPI document exposed by the Agor daemon.
Need the exact schema for your installed version? Start Agor and fetch
http://localhost:3030/docs.json. The/docsroute now brings you back to this maintained reference instead of installing a separate documentation application on every machine.
Quick Reference
Base URL
http://localhost:3030Authentication
Every request carries a bearer credential — either a short-lived access token
from password login, or a personal API key (agor_sk_…):
Authorization: Bearer <your-token-or-api-key>Personal API keys
Create a key in the web UI under your user settings → API tokens. It is
shown once. Keys act as you, never expire on their own, and stop working as
soon as you delete them. They also work as X-API-Key: agor_sk_…, including on the /mcp
endpoint.
Signing in to the CLI
On deployments that sign in with Google or another SSO provider instead of
passwords, such as Agor Cloud, agor login uses your browser:
agor login --url https://your-workspace.example.comThe CLI prints (and opens) a page in your workspace. Sign in if asked, click
Create CLI key, and paste the key into the terminal. The key is tagged
CLI under API tokens and named after the machine
(agor-cli-<hostname>-<id>); logging in again on the same machine replaces it,
so each machine has one. agor logout deletes that machine’s key on the server
(--keep-key only removes the local login). Use --web to pick the browser
flow on a deployment that also has password login.
To use a key you created yourself instead:
agor login --url https://your-workspace.example.com --api-key
# paste the key at the prompt, or pipe it in:
pbpaste | agor login --url https://your-workspace.example.com --api-keyEither way the CLI checks the key against the deployment, saves it to
~/.agor/cli-token (mode 0600), and sends it on every later command. Keys are
never accepted on the command line and never sent to a plain http:// URL other
than localhost. agor logout does not delete keys you created yourself, since
they may be used elsewhere. For CI, AGOR_API_KEY with DAEMON_URL and
AGOR_DEPLOYMENT_ID still works without a saved login.
Keys are bound to the workspace they were created in. On a multi-tenant deployment the daemon uses the workspace URL you connect to to decide which workspace to check the key against, and the key must belong to that workspace. A key presented at another workspace’s URL is rejected, as is any request to a workspace URL the daemon has not yet seen a browser sign-in for. Use the same URL you open in your browser.
Password login
On deployments with email/password sign-in:
agor loginYou’ll be prompted for your email and password. The access token is saved to
~/.agor/cli-token; it is short-lived (15 minutes), so run agor login again
when commands report that your session expired, or use an API key for longer
work.
Using the token with cURL:
# 1. Get your token (already saved locally)
cat ~/.agor/cli-token
# 2. Use it in curl commands
curl -X GET http://localhost:3030/sessions \
-H "Authorization: Bearer <your-token>"The public API reference is intentionally read-only. Browsers cannot call your
local daemon from agor.live unless you deliberately add that origin to the
daemon’s CORS policy. Use cURL or another local API client for requests; this
avoids broadening the daemon’s default browser trust boundary.
Authentication is always required. On first daemon start, an admin user is auto-created with a random password. The credentials are written to ~/.agor/admin-credentials (mode 0600) and printed once to the daemon log. Use those to log in and obtain a JWT.
Core Services
/sessions- AI agent session management with genealogy (fork/spawn)/tasks- Work units within sessions tracking prompts and execution/messages- Conversation messages with streaming support/repos- Git repository management and branch operations/boards- Spatial organization of sessions with zones and triggers/branches- Git branch isolation for sessions/users- User account management and authentication/mcp-servers- Model Context Protocol server configurations
Response Format
All FeathersJS endpoints return data in this format:
// Single resource
{
data: { id: '...', ... }
}
// List of resources (paginated)
{
data: [{ id: '...', ... }],
total: 100,
limit: 50,
skip: 0
}RESTful Conventions
All services follow standard REST patterns:
GET /service- List items (paginated)GET /service/:id- Get single itemPOST /service- Create new itemPATCH /service/:id- Update item (partial)DELETE /service/:id- Delete item
Session Prompt Endpoint
Use POST /sessions/:id/prompt to send a prompt to an existing session.
curl -X POST http://localhost:3030/sessions/<session-id>/prompt \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"prompt": "Review the latest auth changes for security issues",
"permissionMode": "auto",
"stream": true
}'Possible response shapes:
{
"success": true,
"taskId": "0195d3c0-82df-7a75-b9b3-83f58de12345",
"status": "dispatching",
"streaming": true
}The immediate response is dispatching; the authenticated executor changes the task to running after it connects.
{
"success": true,
"queued": true,
"message": {
"message_id": "0195d3c0-82df-7a75-b9b3-83f58de67890",
"status": "queued"
},
"queue_position": 2
}Task Run Endpoint
POST /sessions/:id/prompt is the simplest way to drive a session. It creates the underlying task and starts execution in one round-trip. If you’d rather create the task as a separate step (e.g. so you have its task_id before triggering execution), POST /tasks followed by POST /tasks/:id/run does the same thing in two calls. This is the path pure-REST harnesses use to skip the MCP transport entirely.
# 1. Create a task (status will be 'created')
curl -X POST http://localhost:3030/tasks \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{
"session_id": "<session-id>",
"full_prompt": "Run the test suite and summarize failures",
"status": "created"
}'
# 2. Trigger executor pickup
curl -X POST http://localhost:3030/tasks/<task-id>/run \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your-token>" \
-d '{ "stream": true }'The response is the patched Task row with status: 'dispatching'; the authenticated executor changes it to running after connecting. The endpoint only accepts tasks in created state on an idle session — queued tasks drain automatically in queue-position order, and busy sessions should be prompted via POST /sessions/:id/prompt (which creates and queues the task atomically).
Message Content Shape
Message content supports both plain text and structured blocks:
stringContentBlock[]
String content example:
{
"role": "assistant",
"content": "Implemented the fix and added tests."
}Structured content example:
{
"role": "assistant",
"content": [
{ "type": "text", "text": "Implemented the fix." },
{ "type": "thinking", "thinking": "Checking edge cases before final response." }
]
}Browser Client Quick Start
import { createClient } from '@agor/core/api';
const client = createClient('http://localhost:3030', true, {
socketAuthentication: { accessToken: '<your-token>' },
});
const sessions = await client.service('sessions').findAll({
query: { $limit: 20 },
});
const promptResult = await client.sessions.prompt(
sessions[0].session_id,
'Summarize current progress and next steps',
{ stream: true }
);
console.log(promptResult);
// Or create the task explicitly first, then trigger execution:
const task = await client.service('tasks').create({
session_id: sessions[0].session_id,
full_prompt: 'Run the test suite and summarize failures',
status: 'created',
});
const runningTask = await client.tasks.run(task.task_id, { stream: true });
console.log(runningTask);The WebSocket bearer is verified during every Socket.IO handshake. A socket
never starts anonymous and cannot change user or tenant through a later
client.authenticate() call. To rotate a browser access token while retaining
the client object and its listeners, supply an accessToken getter and update
its value. A healthy connection keeps its immutable authenticated authority;
the next automatic or explicit transport reconnect invokes the getter and
verifies the fresh token.
WebSocket Events
Real-time updates via Socket.IO:
- WebSocket Events - Real-time event documentation
Source Code
For TypeScript type definitions and service implementations:
- TypeScript types:
packages/core/src/types - Service implementations:
apps/agor-daemon/src/services