API reference

HTTP surface of the Managed Agent API: OpenAI Responses–style agents, workspaces, browser auth, and API keys. API routes live under the path prefix /v1 on the host you choose (see below); /healthz is at the host root.

Base URL

The base URL for clients is an origin only: https:// (or http://) plus hostname and optional port. It does not include a /v1 suffix — every endpoint path in this reference already starts with /v1/ or /healthz. Example: GET https://api.example.com/v1/models.

Production layout (public nginx edge in this repo)

  • API subdomain api.<your-domain> serves /v1/* and /healthz. For the default domain in deployment config, that is https://api.agentsway.dev. Use this origin as AGENT_API_BASE_URL in SDKs and for server-side or command-line clients.
  • Marketing / console hosts www.<domain>, <apex>, and console.<domain> are routed to the playground, but the same edge also reverse-proxies /v1/* and /healthz to the gateway so browser code can call the API same-origin (for example https://www.agentsway.dev/v1/…). That is convenience for the site, not a different API product — the dedicated API host remains api.<domain>.

Local Docker / dev: use whatever origin your edge publishes (see deployments/docker-compose); the gateway process itself listens on api-gateway:8080 behind nginx, not on a public URL unless you expose it.

Conventions

  • Unless noted, requests and responses use JSON with Content-Type: application/json.
  • Authenticated endpoints expect Authorization: Bearer <token>. Pass a workspace API key (sk-…) or a short-lived access JWT from the browser auth flow.
  • The gateway may attach X-Request-ID; echo it when reporting issues or when debugging client-side correlation.
  • Errors use a stable envelope:
    {
      "error": {
        "type": "api_error",
        "code": "unauthorized",
        "message": "…",
        "request_id": "…"
      }
    }

OAuth-style scopes

Protected routes check bearer identity and optionally require scopes. Omitting scopes in this table means any valid session or API key works; specific operations may still enforce role checks upstream.

ScopeTypical use
responses:createPOST /v1/agent, POST /v1/responses
responses:readGET response by id, /children, /events
responses:cancelPOST /v1/responses/{response_id}/cancel (abort active run when it executes on this agent-core replica)
models:readGET /v1/models
api_keys:readList and read metadata for API keys
api_keys:writeCreate, activate, deactivate, delete API keys
workspace_members:readWorkspaces, members, invitations, usage
workspace_members:writeCreate or mutate workspaces, members, invitations

Health

MethodPathAuthRequestResponse
GET/healthzNoneJSON { "status": "ok" }

Models and presets

MethodPathAuthRequestResponse
GET/v1/modelsBearer · models:read{ "object": "list", "data": [{ "id", "object": "model", "owned_by", "capabilities": { provider, streaming, tools, reasoning, … } }] }
GET/v1/presetsBearer{ "object": "list", "data": [{ "preset", "prompt_version", "preset_metadata"?, "policy"?: { plan_mode_preference, sub_agent_preference } }] }. Requires config-core; otherwise 503.

Agent responses

POST /v1/agent and POST /v1/responses accept the same body: OpenAI Responses–style CreateResponseRequest (input required; supply model/models or preset). Extensions include managed memory, plan_mode_preference, and sub_agent_preference. Persisted bodies may include lineage fields such as parent_response_id and root_response_id.
MethodPathAuthRequestResponse
POST/v1/agent · /v1/responsesBearer · responses:createJSON CreateResponseRequest. Set stream: true for SSE; multimodal limits apply to inline images.200 JSON Response (status completed | failed | in_progress | …) or text/event-stream: repeated data lines with JSON event objects (same public event shapes as polling). Errors on the wire use an SSE error event.
GET/v1/responsesBearer · responses:readQuery: limit (1–100, default 20), page_token (opaque cursor from prior page){ "object": "list", "data": [{ "id", "status", "created_at", "completed_at", "model", "preset", "input_preview", "root_response_id", "background" }], "has_more", "next_page_token?" } · top-level runs only.
GET/v1/responses/{response_id}Bearer · responses:readPath id pattern resp_*Stored Response JSON (output array, usage, metadata, …).
POST/v1/responses/{response_id}/cancelBearer · responses:cancelEmpty JSON body acceptable (no fields required){ "interrupted": true | false }; true means this replica had an executing run and asked it to stop. Idempotent.
GET/v1/responses/{response_id}/childrenBearer · responses:read{ "object": "list", "data": [{ "id", "status", "created_at", "completed_at", "root_response_id", "model" }] }
GET/v1/responses/{response_id}/eventsBearer · responses:readQuery: after_sequence (optional int≥0), view = "timeline" (default) | "full"{ "data": [ { "type", "sequence_number", optional response snapshot, deltas, reasoning fields, usage, … } ] } · only public/event types appear (internal audit channels are stripped).

Browser auth (no Bearer on these routes)

MethodPathAuthRequestResponse
POST/v1/auth/signupNone{ "email", "password" · 8–32 ASCII (A-Za-z0-9 + symbols !@#$%^&*()-_=+[]{};:,.?/~), "display_name"? }{ "user_id", "email", "verification_required", "code_expires_at" }
POST/v1/auth/verify_emailNone{ "email", "code" }AuthSession JSON; Set-Cookie refresh when configured.
POST/v1/auth/signinNone{ "email", "password" }AuthSession JSON; Set-Cookie refresh when configured.
POST/v1/auth/refreshNone (needs refresh cookie)Rotated AuthSession JSON; rotated Set-Cookie when configured.
POST/v1/auth/signoutNoneAuthStatus { "status", "message"? }
POST/v1/auth/password_reset/requestNone{ "email" } · emails a single-use **reset link** (token in URL) only when the account exists **and** email is verifiedAuthStatus · message e.g. reset link sent wording
POST/v1/auth/password_reset/confirmNone{ "token", "new_password" } · `token` from emailed link query string; `new_password` same policy as signup / POST /v1/me/passwordAuthStatus
GET/v1/auth/oauth/{provider}/startNonePath provider: google | github; query redirect_url?{ "authorization_url", "state", "expires_at" }
GET/v1/auth/oauth/{provider}/callbackNoneQuery code, state, redirect_url?AuthSession JSON

AuthSession fields include access_token, token_type (always bearer), access_token_expires_at, workspace id/role, and string scope list.

Identity and workspace APIs

MethodPathAuthRequestResponse
GET/v1/meBearer{ "object": "identity", "user_id", "workspace_id", "workspace_name"?, "workspace_role", "api_key_id", "scopes": [] }
GET/v1/me/profileBearer{ "object": "user_profile", "user_id", "email", "display_name", "email_verified", "has_password": boolean }
PATCH/v1/me/profileBearer{ "display_name": string } · replaces profile display name for the authenticated user in the active workspaceUpdated user_profile object
POST/v1/me/passwordBearerSigned-in console: rotate or add via `current_password`/`new_password`; unauthenticated reset uses emailed **link** + `POST /v1/auth/password_reset/confirm` with `token`.{ "status": "ok", "message": string } · e.g. "password added" or "password updated"
GET/v1/workspacesBearer · workspace_members:read{ "object": "list", "data": Workspace[] }
POST/v1/workspacesBearer · workspace_members:write{ "name" }; optional slug, type (personal | team | organization), billing_email201 Workspace
GET/v1/workspaces/{workspace_id}Bearer · workspace_members:readPath wrk_*Workspace · id, name, slug?, type, status, role, billing/plan hints, timestamps
PATCH/v1/workspaces/{workspace_id}Bearer · workspace_members:writePartial · name?, slug?, type?, status?, billing_account_id?, billing_customer_ref?, plan?, usage_limit_monthly?, billing_email?Updated Workspace
POST/v1/workspaces/{workspace_id}/switchBearer · workspace_members:readAuthSession scoped to workspace (browser/session clients)
GET/v1/workspaces/{workspace_id}/usageBearer · workspace_members:read{ "object": "workspace_usage", counts, "recent_api_key_usage": [usage events with paths, ua, authenticated_at, …] }

Members and invitations

MethodPathAuthRequestResponse
GET/v1/workspaces/{workspace_id}/membersBearer · workspace_members:read{ "object": "list", "data": WorkspaceMember[] }
POST/v1/workspaces/{workspace_id}/membersBearer · workspace_members:write{ "user_id" }; optional email, display_name, role?201 WorkspaceMember
PATCH/v1/workspaces/{workspace_id}/members/{user_id}Bearer · workspace_members:writeOptional role?, status?WorkspaceMember
DELETE/v1/workspaces/{workspace_id}/members/{user_id}Bearer · workspace_members:writeWorkspaceMember (inactive state)
GET/v1/workspace_membersBearer · workspace_members:readMembers for the caller’s active workspace ({ object, data })
POST/v1/workspace_membersBearer · workspace_members:writeSame shape as scoped add-member201 WorkspaceMember
PATCH/v1/workspace_members/{user_id}Bearer · workspace_members:writeWorkspaceMember patchWorkspaceMember
DELETE/v1/workspace_members/{user_id}Bearer · workspace_members:writeWorkspaceMember
GET/v1/workspaces/{workspace_id}/invitationsBearer · workspace_members:read{ "object": "list", "data": WorkspaceInvitation[] }
POST/v1/workspaces/{workspace_id}/invitationsBearer · workspace_members:write{ "email" }; optional role?, expires_at?201 invitation; invitation_token returned once when created for manual delivery
DELETE/v1/workspaces/{workspace_id}/invitations/{invitation_id}Bearer · workspace_members:writeWorkspaceInvitation revoked
POST/v1/workspace_invitations/acceptBearer · workspace_members:write{ "invitation_token" }WorkspaceMember

WorkspaceMember includes workspace_id, user_id, role, status, created_at.

API keys

MethodPathAuthRequestResponse
GET/v1/api_keysBearer · api_keys:read{ "object": "list", "data": APIKeyInfo[] } (no raw secrets)
POST/v1/api_keysBearer · api_keys:writeOptional name?, scopes[], expires_at? (unix)201 · includes single-use api_key string sk-* plus metadata
GET/v1/api_keys/{api_key_id}Bearer · api_keys:readPath key_*APIKeyInfo
POST/v1/api_keys/{api_key_id}/activateBearer · api_keys:writeAPIKeyStatus
POST/v1/api_keys/{api_key_id}/deactivateBearer · api_keys:writeAPIKeyStatus
DELETE/v1/api_keys/{api_key_id}Bearer · api_keys:writeAPIKeyStatus (deleted)

Schemas and machine-readable spec

Field-level definitions for payloads (tools, multimodal Input, SSE event types, billing-related workspace fields, etc.) live in the repository OpenAPI document api/openapi/agent-api.v1.yaml. Those schemas track the canonical contract; gateway-only routes documented above include GET /v1/presets, GET /v1/responses, GET /v1/responses/:id/children, and GET /v1/responses/:id/events.