API Overview
ShipOS exposes two API surfaces: a control plane for managing flags and projects, and an edge for evaluating flags globally in under 50ms. This page covers base URLs, authentication, the execution model, audit, and the shared error shape.
Base URLs
The two surfaces live on different hosts and use different keys. Pick the one that matches what you're doing.
| Surface | Base URL | What it does |
|---|---|---|
| Control plane | https://app.shipos.app/api/v1 | Manage flags and projects. See the Flags API. |
| Edge | https://edge.shipos.app | Evaluate flags from your app. See the Edge Evaluation API. |
Authentication
The control plane accepts two authentication modes. Dashboard users authenticate with a Supabase session cookie; programmatic clients and agents authenticate with a bearer key.
Session cookie
Dashboard users are authenticated by their Supabase session cookie. Session users may pass ?orgId=<uuid> on any endpoint to act inside another org they belong to; without it, requests default to their first membership.
Bearer key
Programmatic clients send Authorization: Bearer <key>. Which key works where depends on its kind:
| Credential | Prefix | Works on | Executes mutations |
|---|---|---|---|
| Session cookie | - | Control plane | Directly |
| Agent key | sos_agt_* | Control plane + MCP | Directly |
| Admin key | sos_adm_* | Control plane | Directly |
| SDK key | sos_sdk_* | Edge only | Evaluation only |
SDK keys are edge-only
sos_sdk_*) are rejected on the control plane. They only evaluate flags at the edge. To manage flags programmatically, create an agent or admin key in the ShipOS dashboard under Keys.Here's a request to list your org's projects using a bearer agent key:
curl https://app.shipos.app/api/v1/projects \
-H "Authorization: Bearer sos_agt_xxxxxxxxxxxxxxxxxxxx"Direct execution
A valid credential executes mutations directly, there is no approval or sign-off step. Agent keys (sos_agt_*), admin keys (sos_adm_*), and dashboard sessions all apply changes immediately. Safety comes from two properties that hold for every change: it is audited and it is instantly reversible with the flag's kill switch.
Keep autonomy safe by scoping keys
Audit trail
Every mutation writes an audit row atomically with the change, if the write fails, the audit row is never orphaned. Session users are recorded as actor_type: user. Both agent and admin keys are recorded as actor_type: agent, tagged with their key prefix.
Errors
Every error, across both surfaces, uses the same envelope: an error object with a machine-readable code and a human-readable message.
{
"error": {
"code": "version_conflict",
"message": "The config was updated by someone else. Refetch and retry."
}
}| Status | Meaning |
|---|---|
400 | Malformed request or invalid body. |
401 | Missing or invalid credentials. |
403 | Not permitted. Plan-limit violations use code plan_limit. |
404 | Resource not found (or not visible to your org). |
409 | Conflict. Optimistic-concurrency failures (expectedVersion mismatch) use code version_conflict. |
422 | Well-formed request that fails validation. |
Where to next