Skip to content

REST API

This guide covers the Claude-compatible API under /v1/* on Node and Cloudflare, plus OpenMA extensions under /v1/oma/*. The Console consumes this API. For the Node-only /openai/v1 contract and official OpenAI SDK, follow OpenAI Agents API. Requests and event types differ between the two contracts.

EnvironmentBase URL
Hosted (production)https://app.openma.dev
Hosted (staging)https://app.staging.openma.dev
Self-host (Node)http://localhost:8787 by default, or your server origin
Self-host (Cloudflare)Your configured Worker route

Two auth schemes:

API key — for server-to-server and CLI use. Pass as the x-api-key header (x-api-key: oma_...). Create on the Console API Keys page.

Session cookie — what the Console UI uses (better-auth-issued). Not normally what you’ll integrate against unless you’re embedding openma in a browser app.

Terminal window
export OMA_BASE_URL="https://app.openma.dev"
export OMA_API_KEY="oma_..."
GroupPathPurpose
Agents/v1/agentsCreate / read / update / archive agent configurations. Versioned — every update bumps the version.
Sessions/v1/sessionsCreate sessions, list, fetch event log. Live events via SSE.
Environments/v1/environmentsSandbox templates: packages, network rules, base image.
Skills/v1/skillsBuilt-in + custom skill catalog. Custom skill files via R2-backed upload.
Vaults/v1/vaultsCredential stores (bearer tokens, OAuth, env vars).
Memory Stores/v1/memory_storesPersistent files shared across sessions; mounts and versions.
Files/v1/filesPer-session file storage.
Model Cards/v1/oma/model_cardsCustom model provider configuration.
Integrations/v1/oma/integrationsLinear / GitHub / Slack install state, webhooks, publications.
Evals/v1/oma/evalsEvaluation framework.
API Keys/v1/oma/api_keysManage personal access tokens.
OAuth/v1/oma/oauthThird-party OAuth flows for the Console UI.

A full endpoint-by-endpoint reference lives at Reference → API Endpoints.

GET /v1/models is the official Managed Agents catalog and lists the active Model Cards executable by the current tenant. POST /v1/oma/models/list is a separate setup helper that lists models known by a Pi provider; it accepts a Pi provider id and does not require a provider credential on the SDK-first path.

An Agent references a card by model.id. model.effort is normalized through Pi’s supported thinking levels, while model.speed=fast maps to Anthropic fast mode or OpenAI priority service tier. model.inference_geo is round-tripped in the official shape but does not currently affect region routing. All three are Agent-version settings inherited by Sessions, not Model Card configuration.

See API Endpoints → Model Cards for Pi built-in and custom provider rules, pi_config, and probe semantics.

Terminal window
curl -X POST "$OMA_BASE_URL/v1/agents" \
-H "x-api-key: $OMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "research-agent",
"model": "claude-sonnet-4-6",
"system": "You are a research assistant.",
"tools": [{"type": "agent_toolset_20260401"}]
}'
Terminal window
curl -X POST "$OMA_BASE_URL/v1/sessions" \
-H "x-api-key: $OMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"agent": "agent_abc123",
"environment_id": "env_lvqed06glbi3ent0",
"title": "research session"
}'

The response includes the new session’s id (e.g. sess_xyz). Send the first user turn separately — see “Send a turn” below.

Terminal window
curl -N "$OMA_BASE_URL/v1/sessions/sess_xyz/events/stream" \
-H "x-api-key: $OMA_API_KEY"

The connection stays open. Each data: line is a single JSON event.

Default behavior is Anthropic-spec-aligned (Managed Agents events) — only events emitted after open are delivered, and only the spec event types appear:

EventWhen
user.messageEcho of the turn you posted
session.status_running / _idle / _rescheduled / _terminated / errorLifecycle
agent.thinkingExtended-thinking block (whole)
agent.messageAssistant message (whole)
agent.tool_use / agent.mcp_tool_use / agent.custom_tool_useTool call (whole)
agent.tool_result / agent.mcp_tool_resultTool execution result
agent.thread_* / session.thread_*Multiagent coordination
span.model_request_start / _end / span.outcome_evaluation_*Observability

Use the official @anthropic-ai/sdk directly — it parses these unchanged.

Adds finer-grained streaming + extra observability. Required for token-by-token UI rendering.

EventWhen
agent.message_stream_start / _chunk / _stream_endLive assistant-text deltas — chunk events carry { message_id, delta }
agent.thinking_stream_start / _chunk / _stream_endLive extended-thinking deltas — chunk events carry { thinking_id, delta }
agent.tool_use_input_stream_start / _chunk / _stream_endLive tool-input JSON streaming — chunk events carry { tool_use_id, delta }
system.user_message_pending / _promoted / _cancelledPending-queue lifecycle (outbox UX)
session.warningRecovery scan reconciled an interrupted stream / orphan tool_use after a runtime restart
span.model_first_token / span.compaction_summarize_* / span.wakeup_scheduled / aux.model_callExtra observability

Stream-lifecycle events (*_stream_start, *_chunk, *_stream_end) are broadcast over the wire but not persisted to the events log — the canonical event with the same correlation id is the source of truth. Replay clients only see the canonical events; live subscribers see both.

?replay=1 and Last-Event-ID — history replay

Section titled “?replay=1 and Last-Event-ID — history replay”

Default behavior matches Anthropic: no replay, only events after open. To bootstrap clients with persisted history:

  • ?replay=1 — replay the full persisted log on connect, then continue tailing
  • Last-Event-ID: <seq> — replay events with seq > N only (SSE-native resume; browsers send this automatically on reconnect)

Both compose with ?include=chunks. For the open-then-list-then-dedupe pattern (Anthropic’s recommended way to recover history without replay), see GET /v1/sessions/:id/events for the JSON-paginated history.

Terminal window
# Console-style: full history + token-level streaming
curl -N "$OMA_BASE_URL/v1/sessions/sess_xyz/events/stream?include=chunks&replay=1" \
-H "x-api-key: $OMA_API_KEY"

OMA-only convenience endpoint (no Anthropic-spec equivalent). Posts the user message and streams the response in one HTTP call. Always emits chunk events. The connection auto-closes when the turn finishes (session.status_idle).

Terminal window
curl -N -X POST "$OMA_BASE_URL/v1/sessions/sess_xyz/messages" \
-H "x-api-key: $OMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "content": "Now also include the integrations." }'

content accepts a plain string (wrapped as a single text block) or a ContentBlock[] array (mix text + image + document). Returns text/event-stream.

Send a turn into a session that’s already streaming elsewhere

Section titled “Send a turn into a session that’s already streaming elsewhere”

When you want fire-and-forget instead (e.g. you have a separate SSE consumer):

Terminal window
curl -X POST "$OMA_BASE_URL/v1/sessions/sess_xyz/events" \
-H "x-api-key: $OMA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "events": [{ "type": "user.message", "content": [{ "type": "text", "text": "Now also include the integrations." }] }] }'

Returns 202 with no body — the SSE stream you already have open will receive the response events.

Terminal window
curl -X POST "$OMA_BASE_URL/v1/files" \
-H "x-api-key: $OMA_API_KEY" \
-F "session_id=sess_xyz" \
-F "file=@./report.pdf"

The file lands in R2 and is mounted into the sandbox at /home/user/files/<id>/report.pdf.

Standard HTTP status codes. Body shape:

{
"error": {
"type": "invalid_request",
"message": "agent_id is required"
}
}

Common types: invalid_request, not_found, unauthorized, forbidden, rate_limited, internal_error.

Per-tenant. Limits and current usage are surfaced in response headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset (Unix epoch seconds).