API, CLI & SDK
Call Compass over HTTP, from your terminal, or from Python — one surface, three clients, every example in all three.
Everything you can do in the app you can do from outside it. There's one HTTP API underneath, and three ways to call it:
- API — the raw HTTP surface. Use it from any language or tool that can make a request.
- CLI — the
compasscommand. A management surface for your terminal — not just running and inspecting work, but authoring it: create agents, build and deploy workflows, manage connections and datasets, every command scriptable for automation and CI. - Python — the async Compass SDK,
from compass_core import Compass. The same wheel as the CLI, imported as a library.
Pick your client once
Every example on this page comes in all three flavors. Switch any code block to API, CLI, or Python and the whole page follows — the choice is remembered next time you visit.
Install
The CLI and the SDK ship in a single Python wheel you download from the app, at Settings → Developer → SDK & CLI (the Download wheel button). The panel shows the exact file name and the commands to run. The API needs no install at all.

Nothing to install. Calls go to your Compass URL — the same address you use to sign
in — under the /v1 prefix:
https://your-compass-url/v1Authenticate
Every client authenticates with an API key — create one in Settings → Developer → API keys and copy it (it's shown only once).
A key is not a bearer token. It's a self-contained credential that you exchange for a short-lived access token, and that access token is what actually rides on each request. The CLI and the SDK do the exchange for you and refresh it as it expires; over raw HTTP you do it yourself.
Authenticating by hand is three steps: read the values out of your key, exchange them for an access token, then call the API with that token.
1 — Read the values out of your key. The key is base64url-encoded JSON. Any base64url decoder will do; this one needs nothing but Python:
python3 -c "import base64, os; k = os.environ['COMPASS_API_KEY']; print(base64.urlsafe_b64decode(k + '=' * (-len(k) % 4)).decode())"It prints the three values the key carries:
{
"token_url": "https://auth.your-compass-url/application/o/token/",
"client_id": "…",
"client_secret": "…"
}Take token_url from the key rather than guessing it — it's your sign-in provider's
token endpoint, which is a different hostname from the Compass API.
2 — Exchange the key for an access token using the OAuth2 client-credentials grant, posting those three values as form fields:
COMPASS_ACCESS_TOKEN=$(curl -s -X POST "<token_url>" \
-d grant_type=client_credentials \
-d client_id="<client_id>" \
-d client_secret="<client_secret>" \
-d scope=openid | jq -r .access_token)The reply is a standard OAuth2 token response: access_token is the token to send,
and expires_in says how many seconds it stays valid. It's short-lived, so a
long-running caller repeats this exchange when it lapses — which is exactly what the
SDK and CLI do on your behalf. Keep the key; it's what you re-exchange with.
3 — Call the API with that access token as the bearer:
curl https://your-compass-url/v1/projects/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"Every API example below assumes $COMPASS_ACCESS_TOKEN holds a token that's still
valid.
Profiles, options, and environment
CLI credentials are stored in ~/.config/compass/config.json, and you can keep
several profiles (for example, different organizations or environments):
compass config list # show saved profiles
compass config use <name> # switch the default profile
compass config path # where the config file livesA few options apply to every command. They're global, so they go right after
compass, before the command group:
| Option | Purpose |
|---|---|
--profile <name> | Use a saved profile for this command. |
--project <id> | Act in this project for this command. |
-o, --output table|json|yaml | Output format. |
--api-key, --base-url | Override the profile's key or URL. |
compass --project <project-id> -o json workflows listEnvironment variables override the saved profile (and command-line options override both):
| Variable | Purpose |
|---|---|
COMPASS_API_KEY | The API key to authenticate with. |
COMPASS_BASE_URL | Your Compass URL. |
COMPASS_PROFILE | Which profile to use. |
COMPASS_PROJECT_ID | The project to act in (see below). |
Choose a project
Your API key is organization-scoped, so you tell Compass which project a call should act in. Skip it and calls act on your organization's default project.
Send the project's id on each request as a header:
X-Compass-Project-Id: <project-id>GET /v1/projects/ lists the projects your key can reach and your role in each.
Run an execution
Execution is asynchronous: you dispatch work and get back an execution you then
poll or stream until it finishes. Provide either a deployment_id (the live
version) or a workflow_id (the latest draft of a workflow or agent), plus the
input. The response has an id and a status — the id is typed by what you
dispatched: workflow_execution_<hex> or agent_execution_<hex>.
curl -X POST https://your-compass-url/v1/executions/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d '{
"deployment_id": "<deployment-id>",
"input_data": { "topic": "Q3 report" }
}'Optional fields:
| Field | Purpose |
|---|---|
conversation_id | Continue a conversation, for agents with conversation history. |
config | Values for the definition's declared run settings. |
tools, tool_targets | Replace a single agent's tools for this run, and pick live or draft for workflow and agent tools. |
model_settings, reasoning, harness | Override a single agent's sampling settings, reasoning effort, or harness for this run. |
A run can be refused before it starts: 402 when a
spend limit blocks it, 409 when its deployment is
archived.
Get the result
Once dispatched, read the execution by id to check its status and output. Poll
until it reaches a terminal state — or stream it instead.
An execution's status is one of pending, running, waiting_approval (paused
on a human decision), completed, failed, or cancelled
(stopped before it finished). While it runs,
progress (0–1) and current_step say how far along it is. total_cost is its
cost, and rollup_total_cost includes any child executions.
curl https://your-compass-url/v1/executions/<execution-id> \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"Stream it live
For real-time output, subscribe to the execution's event stream — a
Server-Sent Events
connection. Each event is a JSON object with a type: token and reasoning
(text as it's generated), node and batch_item (steps starting and finishing),
tool_call, tool_result, and child_run, approval_requested and
approval_resolved, error, and finally complete. The stream replays from the
start, so you never miss early events, and closes after complete.
Send Accept: text/event-stream — without it, the response is buffered rather
than streamed:
curl -N https://your-compass-url/v1/streams/<execution-id> \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "Accept: text/event-stream"Inspect executions
Beyond the execution itself, you can list your project's executions and read any execution's full trace — per-node details and the hierarchical tree, including child executions.
# List executions in the project, newest first
curl "https://your-compass-url/v1/executions/?status=failed&limit=20" \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>"
# Per-node details, and the hierarchical trace
curl https://your-compass-url/v1/executions/<execution-id>/node-executions \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"
curl https://your-compass-url/v1/executions/<execution-id>/tree \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"The list is paged: it returns {items, next_cursor} — pass cursor to get the
next page. Filter with workflow_id, deployment_id, status, q (search by name
or id), since, and until; limit is up to 200.
GET /v1/executions/summary returns aggregate usage over a time window. The window is
unbounded unless you pass since and/or until. group_by buckets it by workflow,
deployment, day, week or month; pass tz (an IANA zone such as
America/Chicago) to cut days, weeks and months in that zone rather than UTC.
Create an agent
Agents are workflows of type agent, so every client creates
them through the workflows surface from a definition — the same YAML you see in
the builder's YAML view. The CLI adds a first-class agents group on top,
including an interactive wizard.
POST /v1/workflows/ with the definition as a string — YAML or JSON — and,
optionally, a display_name and description. The easiest way to get a
definition to start from is to build one in the app and copy it from the YAML view,
or read the definition field of GET /v1/workflows/{id}:
curl -X POST https://your-compass-url/v1/workflows/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile def agent.yaml '{definition: $def}')"Build, validate, deploy
The whole workflow lifecycle is available from code: create a workflow from a
definition, validate it, and deploy it. Because agents are workflows under the
hood, validate and deploy work on an agent's id too.
# Create
curl -X POST https://your-compass-url/v1/workflows/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d "$(jq -n --rawfile def workflow.yaml '{definition: $def}')"
# Validate — returns { valid, issues }
curl -X POST https://your-compass-url/v1/workflows/<workflow-id>/validate \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN"
# Deploy — freezes the draft into the next version and makes it live
curl -X POST https://your-compass-url/v1/deployments/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d '{ "workflow_id": "<workflow-id>" }'Pass version_id to deploy an existing version instead of the draft. A definition
with validation errors is refused with 422 and the list of issues.
Work with datasets
Datasets can be created, filled, and searched from any client. Uploading a file starts its ingestion and returns the execution, so you can wait for it like any other.
# Create — the embedding model comes from the connection, and can't change later
curl -X POST https://your-compass-url/v1/datasets/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d '{ "display_name": "Policies", "embedding_connection_id": "<connection-id>" }'
# Upload a file, then add it to the dataset
curl -X POST https://your-compass-url/v1/files/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-F file=@handbook.pdf
curl -X POST https://your-compass-url/v1/datasets/<dataset-id>/documents \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d '<the file object returned by /v1/files/>'
# Search
curl -X POST https://your-compass-url/v1/datasets/<dataset-id>/search \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>" \
-H "Content-Type: application/json" \
-d '{ "query": "parental leave", "top_k": 5 }'Sources are managed under /v1/datasets/{id}/sources — see the
reference.
Manage connections
Connections, providers, and gateways can be managed from
any client — creating or changing them needs a key with a
Developer role, because
they hold credentials. Deleting one that's still in use is refused with 409; see
Managing connections.
curl https://your-compass-url/v1/providers/ \
-H "Authorization: Bearer $COMPASS_ACCESS_TOKEN" \
-H "X-Compass-Project-Id: <project-id>"The same shape applies to /v1/connections/ and /v1/gateways/, each with
GET/PATCH/DELETE on /{id} and GET /{id}/usage to see what uses it.
PATCH with {"is_active": false} switches a connection off.
Scriptable end to end
Everything above composes: create an agent, deploy it, kick off an execution, and parse the result — from CI, a script, or your own backend, without the UI.
Reference
HTTP resources
All routes live under https://your-compass-url/v1 and take an
access token as the bearer, plus (optionally) the project header
shown above. Most errors return {type, code, message, context, hint, is_retryable}; a few — such as the 409 for an archived deployment, upload limits,
and request-validation errors — return {detail} instead.
| Resource | Routes |
|---|---|
| Executions | GET/POST /v1/executions/, …/{id}, …/{id}/node-executions, …/{id}/tree, …/summary, POST …/{id}/cancel — stop it; answers 204, then the execution settles as cancelled and its stream closes |
| Streams | GET /v1/streams/{execution_id} — live Server-Sent Events |
| Workflows | GET/POST /v1/workflows/, GET/PATCH/DELETE …/{id}, …/{id}/validate, …/{id}/versions, …/{id}/metrics, GET …/system |
| Deployments | GET/POST /v1/deployments/ (POST deploys), GET/PATCH …/{id}, …/{id}/archive, …/{id}/bindings, …/{id}/triggers, …/{id}/metrics |
| Approvals | GET /v1/approvals/, …/{id}, POST …/{id}/approve, …/{id}/reject |
| Conversations | GET/POST /v1/conversations/, GET/DELETE …/{id}, …/{id}/executions, POST …/{id}/rewind — drop a turn and everything after it, to edit or retry from there |
| Files | POST /v1/files/ — upload a file (up to 20 MB) to attach or ingest |
| Datasets | GET/POST /v1/datasets/, GET/PATCH/DELETE …/{id}, …/{id}/documents, …/{id}/search, …/{id}/sources, …/{id}/sources/{source_id}/sync, …/{id}/runs, …/{id}/reingest, …/pipelines |
| Connections / Providers / Gateways | GET/POST /v1/connections/, /v1/providers/, /v1/gateways/, each with GET/PATCH/DELETE …/{id} and …/{id}/usage |
| Integrations | GET/POST /v1/integrations/, GET/PATCH/DELETE …/{id} — custom (OpenAPI) integrations |
| Spend limits | GET/POST /v1/spend-limits/, PATCH/DELETE …/{id} |
| Projects | GET/POST /v1/projects/, PATCH/DELETE …/{id} |
CLI commands
| Group | What it does |
|---|---|
compass auth | login, logout, whoami. |
compass config | Manage profiles: list, use, path. |
compass projects | list the projects your key can reach, and use one. |
compass workflows | list, get, create, update, delete, validate, deploy. |
compass agents | list, get, create, update, execute, delete. |
compass execute | Dispatch an execution of a deployment or workflow. |
compass executions | Inspect executions: list, get, node-executions, tree; cancel stops a running one. |
compass approvals | list, get, approve, reject human-in-the-loop approvals. |
compass conversations | list, get, create, runs, delete. |
compass datasets | list, show, create, upload, documents, search, delete-document, delete, sources, add-source, sync, runs. |
compass connections · providers · gateways | Manage each kind of connection. |
compass integrations | list, get, register (from an OpenAPI spec), delete. |
compass components · nodes | Browse the component catalog and every node type. |
Run compass --help, or compass <group> --help, to see every option. Most
commands print a readable table by default. For machine-readable output, add
--json to the command, or set the global -o option before the group:
compass workflows list --json
compass -o yaml executions get <execution-id>Python resources
The client groups calls by resource:
| Resource | Use it for |
|---|---|
client.executions | Dispatch executions, read their results and traces, and cancel() a running one. |
client.streams | Subscribe to an execution's live events. |
client.workflows | List, get, create, update, validate, and deploy workflows and agents; system() lists built-in ones such as Compass Chat. |
client.conversations | Group executions into conversations. |
client.approvals | List and decide human-in-the-loop approvals. |
client.files | Upload files to attach to executions. |
client.datasets | Create, fill, sync, and search datasets. |
client.connections | Manage integration connections. |
client.integrations | Manage custom (OpenAPI) integrations. |
client.providers | Manage provider connections. |
client.gateways | Manage gateway connections. |
client.components · client.nodes | Browse the component catalog and every node type. |
client.projects | List the projects your key can reach, with your role. |
Python errors
The SDK raises typed exceptions you can import from compass_core.client:
| Exception | When |
|---|---|
AuthError | The request was refused as unauthenticated or forbidden (401/403) — for example, no access to this project. |
NotFoundError | The resource doesn't exist in your project. |
ValidationError | The request was rejected as invalid. |
RateLimitError | You've been rate limited. The client waits and retries once when the server asks for a short wait; otherwise it raises, with retry_after. |
ServerError | Something failed server-side. |
All of them derive from CompassClientError, which is also raised directly for
other refusals — such as 402 (a spend limit blocked the run) and 409 (a
conflict, such as deleting something still in use). Every error carries
status_code and the response body. A key that can't be exchanged for an access
token — malformed, revoked, or expired — raises CompassClientError before any API
call is made.