oxagenDocs
REST API

API overview

Call the capabilities declared for the authenticated, versioned REST API.

The Oxagen REST API serves capabilities declared for its API surface as versioned HTTP endpoints. Use it for server-to-server integrations, your own tooling, and automation pipelines that do not speak MCP.

Base URL: https://api.oxagen.sh

Current version: v1

Every endpoint sits under /v1/, and the version prefix is required. Workspace-scoped endpoints take the org and workspace slugs as the next two path segments:

https://api.oxagen.sh/v1/{orgSlug}/{workspaceSlug}/agent/tools
                     └┬┘ └───┬───┘ └─────┬─────┘ └────┬────┘
                   version  org     workspace     capability route

Your first request

List the capabilities the workspace offers as agent tools. The call only reads, and it consumes no credits.

bash
curl -X POST "https://api.oxagen.sh/v1/acme/main/agent/tools" \
  -H "Authorization: Bearer $OXAGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "includeExternal": false }'

Each entry in tools carries name, description, domain, category, riskLevel (low, medium, or high), requiresApproval, and external.

Design principles

Declared surfaces. A capability contract declares whether it is exposed on API, MCP, agent, or CLI. Shared handlers use the same kernel, but availability differs by contract. Check the declared surfaces before moving an integration.

Thin shell, shared logic. The API server is a thin routing layer over the shared platform library. Business logic lives in the shared layer, not in route handlers, so the API behaves the same way the app does.

Versioned. Every endpoint carries the /v1/ prefix. A breaking change ships in a new version, with a window where both versions run.

Scoped. A workspace key belongs to one org and one workspace. An organization key belongs to one org and can name any workspace in it. You do not pass orgId or workspaceId in request bodies. The path must name the key's own org and workspace, by slug or ID. A path that names another one gets 403 with error.reason key_scope_mismatch.

Request lifecycle

Loading diagram

Every route is a thin adapter over invoke(). The gates, the meter, and the audit record are the same ones the MCP server and the in-app agent pass through.

Authentication

Authentication has the full reference. In short:

http
Authorization: Bearer ox_…

Every request needs an Authorization header with a Bearer token. A request without a valid token returns 401 Unauthorized. When IAM denies the capability for the calling principal, the request returns 403 Forbidden with a forbidden error code.

Error format

Errors share one envelope. requestId sits beside error, and the x-request-id response header carries the same value. When a refusal has a more specific cause, error.reason names it, for example key_scope_mismatch or approval_expired:

json
{
  "error": {
    "code": "forbidden",
    "message": "IAM denied \"list_agent_tools\" for principal: deny"
  },
  "requestId": "3f1c9a52-7d4e-4b8a-9c1e-2a6f0b5d8e47"
}

Common error codes:

CodeHTTP statusMeaning
unauthorized401Missing, malformed, invalid, or expired token, a key whose workspace is archived, or a key locked to a purpose this route does not serve
forbidden403IAM denied the capability, the capability is not on the API surface, or a role, key scope, or sign-in rule refused the caller. reason names the rule when there is one
pending_approval403The rule requires approval. Oxagen recorded an access request (accessRequestId is included)
decision_rule_denied403A workspace decision rule refused the call. The message names the rule and its description
decision_rule_approval_required403A workspace decision rule wants a person to approve the call first. The API has no way to ask, so the call is refused
insufficient_credits402The org has zero credit balance
billing_suspended402The org subscription is suspended
budget_exceeded402A spend ceiling was reached
gau_exhausted402An org with no subscription has used up or outlived its signup grant. reason says which
not_found404The resource or capability does not exist, or is outside the token's scope
conflict409The request conflicts with the resource's current state. reason names the conflict
validation_error400The request body failed schema validation (details lists the issues)
bad_request400The capability rejected the input
internal_error500Unexpected server error. Include requestId in support tickets
decision_rules_unavailable503Oxagen could not read the workspace's decision rules, so it did not admit the call. Retry shortly
external_rules_unavailable503The server has not loaded the rules for external tools, so it did not run the call. Retry shortly
service_overloaded503The API is at capacity. Retry after the seconds in Retry-After

A rate-limited request is the one exception to the envelope. It returns 429 with the body { "error": "rate_limited" } and a Retry-After header in seconds.

Capabilities and parity

Capabilities explains the contract model, the naming rule, the route conventions, and how to read the capability registry.

Some flows also require a browser redirect or an approval interaction. Consult the operation's route and contract before assuming it can run unattended.

Rate limits

The API enforces rate limits. Past a limit, the response is 429 Too Many Requests with Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Oxagen does not publish per-plan limits. Contact support if you hit sustained rate limiting.

A request body may be up to 4 MiB. A larger body gets 413 with the code bad_request. File uploads to the assistant have their own, larger limit.

Streaming

The chat endpoint (POST /v1/{orgSlug}/{workspaceSlug}/chat/stream) returns a text/event-stream (SSE) response instead of a JSON body. Chat streaming describes the event format.

GET /v1/{orgSlug}/{workspaceSlug}/runs/{runId}/stream streams one run's frames as SSE. Each frame carries an id:. After a dropped connection, resume with the Last-Event-ID header or the after query parameter, and no frame repeats or goes missing.

On this page