ORKESTERA / API DOCUMENTATION

Build with Orkestera.
Keep the tools you use.

Connect a client, route its model calls, or hand a task to Orkestera. This guide walks through authentication, execution and the records you can read back.

Reviewed against Orkestera release 0.4.5 on October 1, 2026. This reference covers implemented external interfaces. It is deployment-aware: use discovery for service URLs and enabled surfaces. The marketing domain is not an API base URL.

Build against a released v1 contract.

The external Client Contract is stable at v1. Released fields keep their names and remain available within v1; releases may add optional fields and error codes. Pin a released source revision and handle additions without assuming that every deployment serves the newest feature. An unmerged draft carries no released compatibility promise.

Recent external API additions
ReleaseWhat became available in source
0.3.0First released v1 contract: discovery, scoped identity, sessions, tasks, client events, OTLP and read-back.
0.4.0Native Responses and JSON compaction on pinned provider/model routes.
0.4.1Separate telemetry-purpose credentials and Client Edge OTLP ingestion.
0.4.5Current application release. Ork Chat's image and audio interfaces use browser sessions; the external v1 operations remain the same.

For event batches, use telemetry.max_batch_bytes and telemetry.max_batch_events from the session handshake. A draft-only telemetry.max_event_bytes field was removed before the first v1 release; do not require it. Accepted run state can be trimmed, so inspect each result's truncated flag and the run's truncation metadata.

START HERE

From access to your first request.

You need access to an Orkestera organization before connecting a client. If you’re joining an existing deployment, ask its administrator for an account, your Auth URL and a registered public client ID. You do not need to install the server on your laptop.

Choose where Orkestera runs

Cloud

The current infrastructure deploys to AWS ECS using CloudFormation, with MongoDB Atlas. This is an operator-managed deployment, not a one-command public installer. Joining an existing cloud deployment only requires your account and client setup below.

Local development

Authorized source users can run the stack with Docker Compose. From the repository root, run ./run.sh, follow its setup prompts and activate the development account using the link it prints. Confirm health with docker compose ps.

On-premises or hybrid

Discuss your network, identity, model hosting and data requirements with the team. The containerized services provide a starting point, but the current repository does not ship a turnkey production on-premises or hybrid installation guide.

Public SaaS · coming soon

The public service is planned at app.orkestera.com. It is not the beta API endpoint or an open signup flow today. Tell us about your use case to express interest.

What do I need to run the stack locally?

Repository access, Docker Engine 24+, Compose 2.30+, Bash, OpenSSL and curl. Give Docker at least 8 GB of memory on macOS or Windows. The setup script configures development DNS and TLS; DNS setup may require administrator rights. Use WSL2 on Windows. A provider credential is needed for inference; repository-writing tasks also need the Runner GitHub App configured.

Follow the repository README supplied with your checkout for credential provisioning and OS-specific setup. Local development uses auth.orkestera.test and api.orkestera.test; it is a development environment, not a production installation recipe. Trust the development CA explicitly rather than disabling TLS verification.

INVITED BETA TESTERS

Connecting to ork.edos.io

Use the account and organization access arranged with the beta team. Ask for your registered client ID and confirmation that external inference is enabled for your organization.

Portal / account access
https://ork.edos.io
Auth issuer
https://auth.ork.edos.io
Client inference origin
https://api.ork.edos.io
OpenAI-compatible base URL
https://api.ork.edos.io/v1
Task API origin
https://platform.ork.edos.io

The portal is for people; api.ork.edos.io is for model requests. Anthropic clients use the inference origin without /v1; OpenAI-compatible clients use the base URL with /v1. Do not append that prefix twice.

export ORK_AUTH_URL='https://auth.ork.edos.io'
export ORK_EDGE_URL='https://api.ork.edos.io'
export ORK_CLIENT_ID='REPLACE_WITH_YOUR_REGISTERED_CLIENT_ID'

These host mappings were checked against public discovery on September 25, 2026. Check discovery again below: an advertised endpoint identifies a surface, not proof that your account or model route is ready.

1. Check access and discover endpoints

For another deployment, replace the Auth URL above with the one your administrator supplies. You’ll need curl for these examples. This first check does not need a token or run a model.

curl --fail-with-body \
  "$ORK_AUTH_URL/.well-known/orkestera-client-contract"

curl --fail-with-body \
  "$ORK_AUTH_URL/.well-known/oauth-authorization-server"

Expect JSON containing the issuer, OAuth endpoints and service URLs. The contract’s endpoints.inference_openai is the full Chat Completions URL, not a base URL. An unavailable surface is null; stop and ask your administrator rather than guessing a hostname. Set ORK_EDGE_URL to the inference origin for your deployment.

Before inference, an administrator must configure an organization model route backed by a provider credential in Core, register the client with the device and refresh grants, permit audience client_edge and scope inference:write, and allow an appropriate external execution posture. A provider API key is not an Orkestera login token.

For routed external inference, Core owns provider credentials: the organization's credential for the route's provider takes precedence; if that provider is absent, its operator-managed deployment credential can be used. Seeded routes can be visible before their provider is configured. Confirm the route's protocol, model and credential readiness; a model listed by discovery is not a successful inference test. Native Messages and Responses requests need a matching route and compatible dialect; they do not silently substitute an unrelated model.

2. Install the ork credential helper

ork runs on your machine and refreshes short-lived tokens through your OS keychain. The current installation path is a source build: request repository access from the team and install Go 1.25 or newer. There is no published Homebrew package or release-binary installer documented yet.

# From an authorized Orkestera checkout:
cd ork
go install .
export PATH="$(go env GOPATH)/bin:$PATH"
ork --help

If you use a custom GOBIN, add that directory to your PATH instead. Alternatively, build a binary with go build -o ork . and move it to a directory already on your PATH. macOS uses Keychain, Windows uses Credential Manager, and Linux requires a running Secret Service keyring and session bus. A headless Linux shell without a keyring cannot store this login.

3. Sign in for inference

ork login --profile inference \
  --auth-url "$ORK_AUTH_URL" --client-id "$ORK_CLIENT_ID" \
  --audience client_edge --scope inference:write \
  --posture observed --edge-url "$ORK_EDGE_URL"

ork status --profile inference

Open the verification URL printed by ork login, sign in, check that the displayed code matches and approve. The command completes after approval. ork status should show the selected profile, audience and scope without printing your token. The requested posture is bounded by organization policy; observed measures external execution without claiming to enforce the client’s local tools.

4. Make a safe, read-only request

curl --fail-with-body "$ORK_EDGE_URL/v1/models" \
  -H "Authorization: Bearer $(ork token --profile inference)"

Expect a JSON model list with IDs from your organization’s routes. This does not create a task or request a model completion. An empty list means you need a configured route before continuing. Keep tokens out of screenshots, logs and shared configuration.

Optional: try a small model request

This sends a prompt to the configured provider and may incur usage cost. Replace YOUR_MODEL_ID with a listed model backed by a Chat Completions-compatible route. Legacy route names such as FREE-EXEC do not mean free inference; configured models and provider rates determine cost.

curl --fail-with-body "$ORK_EDGE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $(ork token --profile inference)" \
  -H 'Content-Type: application/json' \
  --data '{"model":"YOUR_MODEL_ID","messages":[{"role":"user","content":"Reply with hello."}]}'

Expect a Chat Completions response with an assistant message in choices. For a native Responses route, use the Responses example instead.

5. Connect your client

ork env codex --profile inference --edge-url "$ORK_EDGE_URL"

This prints configuration; it does not install or edit the client. Merge the snippet into your client’s configuration, keep its command-backed authentication and select a served model with a compatible protocol. For Codex, choose a native Responses route. See Clients & tooling for tested versions, other client profiles and protocol limits. To add session and tool observations, follow the optional Codex telemetry setup after inference works. Client-side tools remain with the client; provider-hosted tools remain upstream.

Writing your own client instead of using ork?

Interactive public clients can use the device grant directly. Use a registered client ID, then show the returned verification URL and user code.

curl --fail-with-body "$ORK_AUTH_URL/oauth/device_authorization" \
  --data-urlencode "client_id=$ORK_CLIENT_ID" \
  --data-urlencode 'resource=client_edge' \
  --data-urlencode 'scope=inference:write' \
  --data-urlencode 'posture=observed'

Set ORK_DEVICE_CODE to the returned device code. Poll at the returned interval:

curl --fail-with-body "$ORK_AUTH_URL/oauth/token" \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
  --data-urlencode "client_id=$ORK_CLIENT_ID" \
  --data-urlencode "device_code=$ORK_DEVICE_CODE"

Continue on authorization_pending, slow down on slow_down, and stop on denial or expiry. Store tokens securely and replace refresh tokens after rotation. Confidential server clients can use client credentials instead.

If something doesn’t work

  • Login denied: confirm organization membership, client ID, grants and allowed scopes with your administrator.
  • Keychain unavailable / exit 4: unlock your keyring or use a desktop session with the supported OS credential store.
  • 401: run ork status --profile inference; sign in again if needed. Check the Auth issuer and token audience.
  • 403: inspect the error code. Scope and posture are policy decisions; requesting a different value cannot bypass them.
  • 404 or an HTML page: check the hostname and API prefix. The portal URL is not the inference API.
  • Empty models, dialect mismatch or upstream errors: ask the administrator to check the organization route, protocol and provider credential.

Later examples use ORK_TOKEN as a placeholder for a current access token. Set it with ORK_TOKEN="$(ork token --profile inference)" immediately before those requests; refresh it when it expires rather than saving it in client configuration.

Once inference works, use separate service tokens for tasks, sessions or telemetry. An inference login does not authorize those services.

Use a token for the service you’re calling.

Send Authorization: Bearer <Service Token>. Service Tokens are short-lived and issued for one audience. Mint or refresh the appropriate token for each service; a token for inference does not authorize task creation or telemetry.

External API audiences and scopes
Audience Scopes Use
client_edge inference:write Models, inference and reported usage
core client:session Session handshake
watch client:ingest, watch:read Telemetry writes and read-back, respectively
platform tasks:read, tasks:write Task reads and mutations, respectively
platform workflows:read, workflows:run Published workflows and their runs

The organization, client and user come from verified token claims. Do not send attribution headers to choose another identity. Refresh tokens rotate: replace the previous refresh token with the newly returned one.

When opening a client session, send a descriptor with contract_version, session_id, client_kind, client_version, harnesses, can_enforce_policy and requested_posture. The kind and version must match the token's claims. Mint a token with the right version first; a handshake cannot repair a mismatch or change the token's effective posture. can_enforce_policy is a client hint, not proof of enforcement.

Confidential client token example
curl --fail-with-body "$ORK_AUTH_URL/oauth/token" \
  --user "$ORK_CLIENT_ID:$ORK_CLIENT_CREDENTIAL" \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode 'resource=client_edge' \
  --data-urlencode 'scope=inference:write' \
  --data-urlencode 'posture=observed'

Keep credentials in your application’s secret store. Do not embed them in a public client or browser application.

Posture describes who executes and enforces.

governed delegates execution to Orkestera. client_enforced means the approved client is responsible for enforcing policy. observed means external execution is measured without a claim that Orkestera enforces its local tooling. The organization’s policy and deployment settings determine which postures are available. Missing posture resolves to governed.

A Client Ingest Credential has one immutable purpose. Inference-purpose credentials serve eligible clients that cannot refresh a bearer token. Telemetry-purpose credentials authorize only the Edge’s OTLP ingestion path and require an explicit Watch ingest grant. Neither purpose authorizes tasks, sessions or read-back; the credential is presented to Client Edge, never directly to Watch. Old inference credentials do not gain telemetry access. See telemetry provisioning and rotation.

Your client keeps its tools.

Orkestera’s external interfaces are protocol-based. Integrations are not limited to a named client. Use a client that speaks an implemented protocol and authenticate under your organization’s policy.

Chat Completions carries tool definitions, tool calls and tool results according to the selected route’s capabilities. Anthropic Messages supports native Messages routes; other route dialects can require translation. A route that cannot carry the request may return dialect_mismatch. Model and provider capabilities still apply.

The client executes its local tools and reports their results. Sending a tool definition does not make Orkestera execute a local shell, access client files or host a client’s MCP server. Use client.tool telemetry to report externally executed tools. Keep tool payloads intact; disabling tools is not an integration requirement.

Native Responses is implemented. The current source supports POST /v1/responses and POST /v1/responses/compact through Client Edge. Check your deployment’s discovery document before using them.

Use a native Responses route

In Core, configure a Responses route pinned to one provider and one model. The upstream must support the features your client requests. Existing Chat Completions routes keep their dialect; a continuation never silently switches provider or model.

curl -N --fail-with-body "$ORK_EDGE_URL/v1/responses" \
  -H "Authorization: Bearer $ORK_TOKEN" \
  -H 'Content-Type: application/json' \
  --data '{"model":"YOUR_RESPONSES_MODEL","input":"Review the checkout flow","store":false,"stream":true}'

Native function, custom-grammar, MCP, deferred, namespaced and provider-hosted tool payloads pass through without translation or tool-type filtering. Authentication, scope and posture policy still apply. Keep the complete input history, including tool results and opaque reasoning or compaction items. The client and upstream still own tool execution and availability.

Use stateless replay with store: false. Stored response IDs, conversation references, background jobs, retrieval/cancellation routes and WebSockets are outside this interface. Close the HTTP request to cancel ongoing work. Compaction returns JSON for reuse in later input; it does not stream. Treat failed, incomplete or missing terminal events as an unsuccessful generation.

Codex CLI: what has been exercised

The integration evidence covers unmodified Codex CLI 0.156.1 through the actual Client Edge and inference proxy: shell execution, file edits, custom patches, deferred MCP tools, token refresh and forced compaction against protocol fixtures. A live-provider run exercised patches, MCP tools and tests; it did not force compaction. Desktop and ChatGPT UI compatibility require their own validation; the CLI result does not establish either.

After signing in with ork login for audience client_edge and scope inference:write, use ork env codex to generate the provider configuration. Merge it into your configuration and select a served Responses model with codex --model MODEL. The generated auth helper refreshes the token. Prefer a model ID the client recognizes; a custom alias needs compatible client model metadata.

Opt in to Codex session and tool telemetry

Codex CLI 0.156.1 can now export its own observations through Client Edge. Inference continues to use the rotating token helper and native Responses tools. Telemetry uses a separate, telemetry-purpose Client Ingest Credential; enabling it does not widen your inference credential’s permissions.

This capability is in the released v1 surface from application release 0.4.1. Before configuring the exporter, check your deployment’s discovery document for non-null edge_otlp_logs and edge_otlp_metrics endpoints, and confirm rollout with your administrator. The beta host list above does not establish telemetry readiness.

  1. Ask your administrator or beta team to arrange provisioning for your account with purpose=telemetry. Your client registration must explicitly permit audience watch and scope client:ingest, and current membership and policy must allow observed execution. Provisioning uses the administrator API; a Core provisioning page is not available yet.
  2. Save the once-returned credential in an owner-private file outside your checkout. Never paste it into a shell command, project configuration, screenshot or log. On Unix, use mode 0600; Windows uses owner-restricted ACLs. The CLI checks the file’s protection.
  3. Generate a new private configuration file with the updated ork helper:
# ORK_EDGE_URL is the discovered Client Edge origin, without /v1.
ork env codex --profile inference --edge-url "$ORK_EDGE_URL" \
  --telemetry-credential-file "$HOME/.config/ork/codex-telemetry" \
  --output "$HOME/.config/ork/codex-config.toml"

The output parent directory must exist and be outside Git. The command refuses existing output files, insecure input permissions and credential-bearing output inside a checkout. It writes a private file without printing its credential. Merge it into your private user-level ~/.codex/config.toml, keep its permissions private and restart Codex. Project-local telemetry settings are ignored by the tested CLI. Its static OTLP header does not expand an environment-variable placeholder, so use the generated private configuration.

The generated profile sends JSON logs to the Edge’s /client/v1/otlp/v1/logs endpoint, with metrics and traces disabled. The gateway also accepts OTLP/HTTP JSON or protobuf logs and metrics from other registered clients with the explicit telemetry grant. No gRPC or traces endpoint is provided; no client user-agent allowlist is applied.

To rotate, issue a new telemetry credential, regenerate a new private configuration, restart Codex, then revoke the old credential. The exporter cannot refresh a static header itself. Edge exchanges it for a short-lived Watch token and rechecks authorization as that token expires; its cache bounds revocation delay to five minutes. Credentials default to 30 days and can be issued for at most 90 days.

What appears in Watch?

Conversation starts, tool decisions and tool results can now appear alongside per-response token metadata. Prompt text, tool arguments and raw output are dropped before persistence. Initial sandbox and approval settings are self-reported; they do not attest enforcement or a complete permission-change history. Exports are best effort, and interruptions can lose observations.

Codex does not report a session-ending event or per-conversation monetary cost. Its observed run can remain nonterminal. OTLP token counts are metadata, not an additive billed run total; gateway accounting remains authoritative and enabling telemetry does not bill inference twice. No guaranteed join from a conversation to gateway spend is claimed. Provider-hosted tool surcharges are not separately included in the token ledger.

A local test kept one unmodified CLI process running for 15 minutes 31.8 seconds across four actual token exchanges and 17 authenticated export batches. It used scripted inference and fixture identity services; this proves the refresh path under test, not deployed availability or desktop/ChatGPT compatibility.

Telemetry authentication and delivery errors

At the Client Edge OTLP origin, only a telemetry-purpose credential is accepted. An inference credential or direct Service Token is refused. Watch’s direct OTLP origin still uses a watch Service Token with client:ingest. Identity is rebuilt from verified claims, never accepted from client identity headers.

The Edge bounds compressed and expanded requests to 8 MiB and limits concurrent exports and per-principal request rate. Watch applies its own batch and record limits. Handle 429 using Retry-After, inspect OTLP partial-success responses even on HTTP success, and treat authentication failures as a reason to check purpose, expiry and policy. The logs partial-success field is rejectedLogRecords. Edge can also return 400 invalid_batch, 413 batch_too_large, 415 unsupported_media_type for unsupported content encoding, 403 policy_rejected for identity/posture failure, or 503 upstream_unavailable.

Ork Chat: goals, images and optional audio.

Platform's browser conversation is now Ork Chat. It brings your messages and Ork's replies into one thread, with task work groups, progress narration and a composer that keeps your draft. The welcome greets you by first name when Auth has one; the header shows Platform's current state. The Executive interprets the goal and hands tasks to Runner, which launches one GraphAgent process per run to plan, execute and evaluate the graph.

The composer's Stop control interrupts the pending chat turn. If task submission was already in flight, the task can still start and is shown when the result arrives. Check its task card and use the task's halt control to stop governed execution; stopping a reply is not a task halt.

Attach an image

Select, paste or drop PNG, JPEG, GIF or WebP images into the composer: up to four per message, 5 MB each. The browser prepares images at up to 2048 pixels on their longest edge; a resized GIF becomes a static image. Sent images appear as tiles with a lightbox when storage is available. Image understanding depends on the selected model and provider route supporting vision.

Images stored in the configured artifacts bucket expire after 30 days. The local fallback uses memory and does not promise persistence across a restart. An expired, missing or unsaved image shows its attachment label instead of claiming the image is still available. Reads are scoped to the signed-in user and organization; the media ID grants no independent access. Image content is sent to the selected inference provider, and LLMProxy omits image bytes from its stored inference previews. Chat storage and upstream provider retention still apply.

Dictate a draft or read a reply aloud

Dictation starts only when you choose the microphone and approve browser access. Recording stops after two minutes; the server accepts at most 10 MiB of supported audio. It sends the clip to the configured transcription provider and returns text to the composer for editing. Nothing is submitted as a goal until you send the draft. Platform discards the request's audio and does not store or log the transcript; a draft you later send becomes ordinary chat text.

Dictation requires a supported browser, a provider credential and an operator-selected ORK_TRANSCRIPTION_MODEL (provider/model). It is off by default; the checked-in cloud target settings do not select a transcription model. There is no microphone prompt while it is off. Provider transcription charges are not represented in Platform's token-priced Spend view. Read aloud uses browser speech synthesis, starts only on request, skips code blocks and makes no Platform transcription or inference request.

Platform browser media interfaces
Method and pathAuthenticationResponse
GET /chat/media/{id}Signed-in browser session; owner-scoped 200 image bytes with private caching; 404 for missing, expired or another owner's image; 503 when storage is unavailable. An unauthenticated browser is redirected to sign in.
POST /api/chat/transcriptionsBrowser session and CSRF token Raw audio body with its Content-Type; 200 {"text":"…"}. JSON errors include 400 empty/unreadable clip, 403 missing organization, 404 dictation disabled, 413 too large, 415 unsupported format, 422 no speech, 502 provider failure and 503 missing configuration.

These routes support the signed-in Platform interface. A Client Edge or Platform Service Token does not replace their browser session or CSRF requirements. They are outside the downloadable external Client Contract; the composer uploads images through LiveView, without a public image-upload API.

Where do I find longer-term history?

Watch’s client APIs show activity within its retention window. For longer-term usage, authorized organization administrators use Platform’s Spend page and its exports. Authorized administrators can export audit history through Core. These views depend on the Analytics service being configured and the organization holding the analytics entitlement.

Analytics keeps organization-partitioned copies of inference usage and audit records in Parquet and queries them with DuckDB. The source service stores remain authoritative. Reported usage and Orkestera-routed usage stay separate, and missing prices are not treated as zero.

Watch's GET /api/inference is an operational snapshot with mixed coverage: by_task and by_agent select the caller's organization-owned slices, while by_model, totals and latency are fleet aggregates without tenant keys. Use the entitled organization's Spend views for organization usage estimates; do not read Watch's fleet totals as your organization's billed spend. An older upstream snapshot with no owned slices produces empty task and agent maps, not proof of zero usage.

Terminal governed tasks can also retain a bounded historical trace in Analytics for 30 days, when configured and entitled. This is a compact record for historical investigation, not a complete transcript or an extension of every live Watch event. It is capped at 128 events and 64 KiB, excludes prompts and tool content, and is used when current task events are absent. It does not create a new public Client Edge query endpoint.

The Analytics query, export and purge interfaces are service interfaces inside the deployment. They are not routes exposed by Client Edge or part of the downloadable external Client Contract. A token scope alone does not make an internal service publicly reachable.

Streaming, telemetry and recovery.

For streaming inference, request "stream": true and consume server-sent events incrementally. A successful HTTP connection is not proof that a generation completed; handle in-stream errors and disconnects. Use curl -N when trying streaming requests in a terminal.

Task progress uses GET /api/events with Accept: text/event-stream. Save each event’s id and reconnect with Last-Event-ID. On stream_reset, re-read the tasks you follow before relying on later events.

curl -N "$ORK_PLATFORM_URL/api/events" \
  -H "Authorization: Bearer $ORK_TASK_TOKEN" \
  -H 'Accept: text/event-stream'

For external execution, open a client session and send client.* event batches to Watch. A client.run snapshot replaces the complete run state; sequenced updates must follow consecutively. A sequence gap returns snapshot_required. Partial reporters can use unsequenced merge events, which do not claim complete history.

Inspect every result in an ingest response: acceptance is per event. Retry a batch using its original event IDs. Accepted data can be trimmed to retention and storage limits, exposed through truncation metadata; missing usage or risk reports are not evidence of zero usage or safe execution. Usage reported through /v1/usage is recorded separately from inference purchased through Orkestera and does not debit the organization’s inference budget.

THE API REFERENCE

Look up an endpoint.

Identity & discovery

RFC 8414 authorization server metadata

Audience: — · Public discovery

Public OAuth metadata: issuer, token and device authorization endpoints, supported grants and scopes, and the public signing-key URL.

Responses
StatusMeaning
200OK
Full operation contract
{
  "summary": "RFC 8414 authorization server metadata",
  "description": "Public OAuth metadata: issuer, token and device authorization endpoints, supported grants and scopes, and the public signing-key URL.",
  "x-orkestera-surface": {
    "service": "auth",
    "status": "live",
    "issue": null,
    "gate": null,
    "audience": null
  },
  "x-orkestera-errors": [],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://auth.orkestera.test"
        }
      },
      "description": "Auth: identity and discovery."
    }
  ],
  "security": [],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AuthorizationServerMetadata"
          }
        }
      }
    }
  }
}

JSON Web Key Set

Audience: — · Public discovery

Public signing keys for Service Token verification. Services perform authoritative signature, issuer, audience and expiry checks.

Responses
StatusMeaning
200OK
Full operation contract
{
  "summary": "JSON Web Key Set",
  "description": "Public signing keys for Service Token verification. Services perform authoritative signature, issuer, audience and expiry checks.",
  "x-orkestera-surface": {
    "service": "auth",
    "status": "live",
    "issue": null,
    "gate": null,
    "audience": null
  },
  "x-orkestera-errors": [],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://auth.orkestera.test"
        }
      },
      "description": "Auth: identity and discovery."
    }
  ],
  "security": [],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/JWKS"
          }
        }
      }
    }
  }
}

Client-contract discovery document

Audience: — · Public discovery

Discover supported contract versions and service endpoints for this deployment. A surface that is not advertised is null. Use these URLs instead of guessing hostnames. A non-null URL does not establish your account permissions, provider configuration or service health.

Responses
StatusMeaning
200OK
Full operation contract
{
  "summary": "Client-contract discovery document",
  "description": "Discover supported contract versions and service endpoints for this deployment. A surface that is not advertised is null. Use these URLs instead of guessing hostnames. A non-null URL does not establish your account permissions, provider configuration or service health.",
  "x-orkestera-surface": {
    "service": "auth",
    "status": "live",
    "issue": null,
    "gate": null,
    "audience": null
  },
  "x-orkestera-errors": [],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://auth.orkestera.test"
        }
      },
      "description": "Auth: identity and discovery."
    }
  ],
  "security": [],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/client-contract-document.schema.json"
          }
        }
      }
    }
  }
}

Token endpoint: client_credentials, refresh_token, device_code

Audience: — · See identity guide

Obtain a short-lived Service Token for one resource using client credentials or an approved device code, or rotate a refresh token. The requested posture can only lower the access allowed by policy. Inspect the OAuth error code as well as the HTTP status; token errors currently use 401.

Request schema · application/x-www-form-urlencoded
{
  "type": "object",
  "required": [
    "grant_type"
  ],
  "properties": {
    "grant_type": {
      "type": "string",
      "enum": [
        "client_credentials",
        "refresh_token",
        "urn:ietf:params:oauth:grant-type:device_code"
      ]
    },
    "client_id": {
      "type": "string"
    },
    "client_secret": {
      "type": "string"
    },
    "scope": {
      "type": "string",
      "description": "Space-separated."
    },
    "resource": {
      "type": "string",
      "description": "The audience: auth, core, watch, platform, llmproxy, runner (and the Client Edge's, )."
    },
    "refresh_token": {
      "type": "string"
    },
    "device_code": {
      "type": "string",
      "description": "Live since."
    },
    "posture": {
      "$ref": "./schemas/common.schema.json#/$defs/posture",
      "description": "Caps the resolved posture and never raises it. Absent or unknown caps at governed."
    },
    "client_version": {
      "type": "string",
      "description": "Pending. Required for client_enforced."
    }
  }
}
Responses
StatusMeaning
200OK
400RFC 6749 §5.2 error with a stable code.
401RFC 6749 §5.2 error with a stable code.
429Error with a stable code.
Full operation contract
{
  "summary": "Token endpoint: client_credentials, refresh_token, device_code",
  "description": "Obtain a short-lived Service Token for one resource using client credentials or an approved device code, or rotate a refresh token. The requested posture can only lower the access allowed by policy. Inspect the OAuth error code as well as the HTTP status; token errors currently use 401.",
  "x-orkestera-surface": {
    "service": "auth",
    "status": "live",
    "issue": null,
    "gate": null,
    "audience": null
  },
  "x-orkestera-errors": [
    "invalid_client",
    "invalid_grant",
    "invalid_scope",
    "unsupported_grant_type",
    "unauthorized_client",
    "invalid_target",
    "unauthorized_audience",
    "unauthorized_org",
    "unauthorized_user",
    "rate_limit_exceeded",
    "authorization_pending",
    "slow_down",
    "access_denied",
    "expired_token"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://auth.orkestera.test"
        }
      },
      "description": "Auth: identity and discovery."
    }
  ],
  "security": [
    {
      "clientSecretBasic": []
    },
    {}
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/x-www-form-urlencoded": {
        "schema": {
          "$ref": "#/components/schemas/TokenRequest"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/TokenResponse"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/TokenError"
    },
    "401": {
      "$ref": "#/components/responses/TokenError"
    },
    "429": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: invalid_client, invalid_grant, invalid_scope, unsupported_grant_type, unauthorized_client, invalid_target, unauthorized_audience, unauthorized_org, unauthorized_user, rate_limit_exceeded, authorization_pending, slow_down, access_denied, expired_token

RFC 8628 device authorization request

Audience: — · See identity guide

Start interactive sign-in for a registered public client. Show the returned verification URI and user code, then poll the token endpoint at the returned interval. Approval is bound to the client's organization and the approving user.

Request schema · application/x-www-form-urlencoded
{
  "type": "object",
  "required": [
    "client_id"
  ],
  "properties": {
    "client_id": {
      "type": "string"
    },
    "scope": {
      "type": "string"
    },
    "posture": {
      "$ref": "./schemas/common.schema.json#/$defs/posture"
    },
    "client_version": {
      "type": "string"
    }
  }
}
Responses
StatusMeaning
200OK
400RFC 6749 §5.2 error with a stable code.
401RFC 6749 §5.2 error with a stable code.
429RFC 6749 §5.2 error with a stable code.
500RFC 6749 §5.2 error with a stable code.
Full operation contract
{
  "summary": "RFC 8628 device authorization request",
  "description": "Start interactive sign-in for a registered public client. Show the returned verification URI and user code, then poll the token endpoint at the returned interval. Approval is bound to the client's organization and the approving user.",
  "x-orkestera-surface": {
    "service": "auth",
    "status": "live",
    "issue": null,
    "gate": null,
    "audience": null
  },
  "x-orkestera-errors": [
    "invalid_client",
    "unauthorized_client",
    "invalid_target",
    "invalid_scope",
    "unauthorized_org",
    "rate_limit_exceeded",
    "server_error"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://auth.orkestera.test"
        }
      },
      "description": "Auth: identity and discovery."
    }
  ],
  "security": [
    {}
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/x-www-form-urlencoded": {
        "schema": {
          "type": "object",
          "required": [
            "client_id"
          ],
          "properties": {
            "client_id": {
              "type": "string"
            },
            "scope": {
              "type": "string"
            },
            "posture": {
              "$ref": "./schemas/common.schema.json#/$defs/posture"
            },
            "client_version": {
              "type": "string"
            }
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/DeviceAuthorizationResponse"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/TokenError"
    },
    "401": {
      "$ref": "#/components/responses/TokenError"
    },
    "429": {
      "$ref": "#/components/responses/TokenError"
    },
    "500": {
      "$ref": "#/components/responses/TokenError"
    }
  }
}

Error codes: invalid_client, unauthorized_client, invalid_target, invalid_scope, unauthorized_org, rate_limit_exceeded, server_error

RFC 7009 token revocation

Audience: — · See identity guide

Revoke a token using confidential-client authentication. Public clients cannot call this revocation endpoint; a user or administrator can revoke their access through Auth.

Request schema · application/x-www-form-urlencoded
{
  "type": "object",
  "required": [
    "token"
  ],
  "properties": {
    "token": {
      "type": "string"
    },
    "token_type_hint": {
      "type": "string"
    }
  }
}
Responses
StatusMeaning
200OK
401RFC 6749 §5.2 error with a stable code.
429Error with a stable code.
Full operation contract
{
  "summary": "RFC 7009 token revocation",
  "description": "Revoke a token using confidential-client authentication. Public clients cannot call this revocation endpoint; a user or administrator can revoke their access through Auth.",
  "x-orkestera-surface": {
    "service": "auth",
    "status": "live",
    "issue": null,
    "gate": null,
    "audience": null
  },
  "x-orkestera-errors": [
    "invalid_client",
    "rate_limit_exceeded"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://auth.orkestera.test"
        }
      },
      "description": "Auth: identity and discovery."
    }
  ],
  "security": [
    {
      "clientSecretBasic": []
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/x-www-form-urlencoded": {
        "schema": {
          "type": "object",
          "required": [
            "token"
          ],
          "properties": {
            "token": {
              "type": "string"
            },
            "token_type_hint": {
              "type": "string"
            }
          }
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/TokenError"
    },
    "429": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: invalid_client, rate_limit_exceeded

Client sessions

Session handshake

Audience: core · client:session

Present the client’s session descriptor, including client_kind and client_version matching the token claims. The response carries the effective posture and, for client_enforced sessions, the policy snapshot and its hash. The handshake does not change the token’s posture. Use the reported batch limits and inspect truncation metadata; there is no released max_event_bytes field.

Request schema · application/json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Session descriptor",
  "description": "What a client presents at the session handshake (POST /client/v1/sessions, ). Every field is the client's own statement. The server checks client_kind and client_version against the token's claims and answers a mismatch with a stable error code; it never raises or lowers the posture Auth stamped into the token. `can_enforce_policy` is a hint only: attestation is decided by the operator's Client Kind registry.",
  "type": "object",
  "required": [
    "contract_version",
    "session_id",
    "client_kind",
    "client_version",
    "harnesses",
    "can_enforce_policy",
    "requested_posture"
  ],
  "properties": {
    "contract_version": {
      "type": "string",
      "enum": [
        "v1"
      ]
    },
    "session_id": {
      "description": "Chosen by the client, unique per session, and carried on every client.* event of the session. Unique only within the token's principal (org_id, client_id, user_id): the server keys the session under the principal, so the same value from another org, client or user is a different session. Use a UUID.",
      "$ref": "common.schema.json#/$defs/identifier"
    },
    "client_kind": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9_]*$",
      "maxLength": 64
    },
    "client_version": {
      "type": "string",
      "minLength": 1,
      "maxLength": 64
    },
    "harnesses": {
      "type": "array",
      "maxItems": 32,
      "items": {
        "$ref": "common.schema.json#/$defs/harness"
      }
    },
    "can_enforce_policy": {
      "type": "boolean"
    },
    "requested_posture": {
      "$ref": "common.schema.json#/$defs/posture"
    }
  },
  "additionalProperties": false
}
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
409Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "Session handshake",
  "description": "Present the client\u2019s session descriptor, including client_kind and client_version matching the token claims. The response carries the effective posture and, for client_enforced sessions, the policy snapshot and its hash. The handshake does not change the token\u2019s posture. Use the reported batch limits and inspect truncation metadata; there is no released max_event_bytes field.",
  "x-orkestera-surface": {
    "service": "core",
    "status": "live",
    "issue": null,
    "gate": "client:session",
    "audience": "core"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "unsupported_contract_version",
    "invalid_descriptor",
    "client_kind_mismatch",
    "client_version_mismatch",
    "policy_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://core.orkestera.test"
        }
      },
      "description": "Core: session handshake and org policy."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "client:session"
      ]
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "./schemas/session-descriptor.schema.json"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/handshake-response.schema.json"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "409": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, unsupported_contract_version, invalid_descriptor, client_kind_mismatch, client_version_mismatch, policy_unavailable

Inference

Models this org may call (OpenAI dialect)

Audience: client_edge · inference:write · Edge alternative: inference-purpose Client Ingest Credential

List model IDs from your organization’s route table. Accepts a Service Token or an eligible inference-purpose Client Ingest Credential. A seeded model can appear before its provider credential is configured; the list does not prove that a completion will succeed.

Responses
StatusMeaning
200OK
401Client Edge error: the stable code is `error.code`.
403Client Edge error: the stable code is `error.code`.
429Client Edge error: the stable code is `error.code`.
502Client Edge error: the stable code is `error.code`.
503Client Edge error: the stable code is `error.code`.
Full operation contract
{
  "summary": "Models this org may call (OpenAI dialect)",
  "description": "List model IDs from your organization\u2019s route table. Accepts a Service Token or an eligible inference-purpose Client Ingest Credential. A seeded model can appear before its provider credential is configured; the list does not prove that a completion will succeed.",
  "x-orkestera-surface": {
    "service": "client_edge",
    "status": "live",
    "issue": null,
    "gate": "inference:write",
    "audience": "client_edge"
  },
  "x-orkestera-errors": [
    "invalid_token",
    "insufficient_scope",
    "client_identity_required",
    "posture_not_permitted",
    "rate_limited",
    "upstream_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://edge.orkestera.test"
        }
      },
      "description": "The Client Edge; location and host decided by."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "inference:write"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/EdgeError"
    },
    "403": {
      "$ref": "#/components/responses/EdgeError"
    },
    "429": {
      "$ref": "#/components/responses/EdgeError"
    },
    "502": {
      "$ref": "#/components/responses/EdgeError"
    },
    "503": {
      "$ref": "#/components/responses/EdgeError"
    }
  }
}

Error codes: invalid_token, insufficient_scope, client_identity_required, posture_not_permitted, rate_limited, upstream_unavailable

Chat completions through Orkestera (OpenAI dialect)

Audience: client_edge · inference:write · Edge alternative: inference-purpose Client Ingest Credential

Send an OpenAI Chat Completions request, streaming or JSON, using an available model route. Organization, user and client attribution come from the token. Inference is charged against the organization's budget in every external-execution posture.

Request schema · application/json
{
  "type": "object",
  "required": [
    "model",
    "messages"
  ],
  "description": "OpenAI Chat Completions request, unchanged."
}
Responses
StatusMeaning
200OK
400Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
401Client Edge error: the stable code is `error.code`.
402Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
403Client Edge error: the stable code is `error.code`.
404Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
429Client Edge error: the stable code is `error.code`.
502Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
503Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
Full operation contract
{
  "summary": "Chat completions through Orkestera (OpenAI dialect)",
  "description": "Send an OpenAI Chat Completions request, streaming or JSON, using an available model route. Organization, user and client attribution come from the token. Inference is charged against the organization's budget in every external-execution posture.",
  "x-orkestera-surface": {
    "service": "client_edge",
    "status": "live",
    "issue": null,
    "gate": "inference:write",
    "audience": "client_edge"
  },
  "x-orkestera-errors": [
    "dialect_mismatch",
    "invalid_token",
    "insufficient_scope",
    "client_identity_required",
    "posture_not_permitted",
    "rate_limited",
    "upstream_unavailable",
    "budget_exceeded",
    "route_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://edge.orkestera.test"
        }
      },
      "description": "The Client Edge; location and host decided by."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "inference:write"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "model",
            "messages"
          ],
          "description": "OpenAI Chat Completions request, unchanged."
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "401": {
      "$ref": "#/components/responses/EdgeError"
    },
    "402": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "403": {
      "$ref": "#/components/responses/EdgeError"
    },
    "404": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "429": {
      "$ref": "#/components/responses/EdgeError"
    },
    "502": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "503": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    }
  }
}

Error codes: dialect_mismatch, invalid_token, insufficient_scope, client_identity_required, posture_not_permitted, rate_limited, upstream_unavailable, budget_exceeded, route_unavailable

Messages through Orkestera (Anthropic dialect)

Audience: client_edge · inference:write · Edge alternative: inference-purpose Client Ingest Credential

Send an Anthropic Messages request, streaming or JSON. Use a bearer credential or X-Api-Key, and the Anthropic-Version header required by your provider. Native Messages routes preserve the protocol; other routes may translate it or reject an unsupported dialect. Inference is charged against the organization's budget.

Request schema · application/json
{
  "type": "object",
  "required": [
    "model",
    "messages",
    "max_tokens"
  ],
  "description": "Anthropic Messages request, unchanged."
}
Responses
StatusMeaning
200OK
400Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code. llmproxy writes the Anthropic shape on this path too, with its own wider `type` vocabulary.
401Client Edge error on /v1/messages, Anthropic-shaped: the stable code is `error.code`.
402Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code. llmproxy writes the Anthropic shape on this path too, with its own wider `type` vocabulary.
403Client Edge error on /v1/messages, Anthropic-shaped: the stable code is `error.code`.
404Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code. llmproxy writes the Anthropic shape on this path too, with its own wider `type` vocabulary.
413Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code. llmproxy writes the Anthropic shape on this path too, with its own wider `type` vocabulary.
429The Edge's rate_limited (a Client Ingest Credential exchanged too often), or llmproxy's upstream_rate_limited, which carries the provider's Retry-After. Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
502Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code. llmproxy writes the Anthropic shape on this path too, with its own wider `type` vocabulary.
503Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code. llmproxy writes the Anthropic shape on this path too, with its own wider `type` vocabulary.
Full operation contract
{
  "summary": "Messages through Orkestera (Anthropic dialect)",
  "description": "Send an Anthropic Messages request, streaming or JSON. Use a bearer credential or X-Api-Key, and the Anthropic-Version header required by your provider. Native Messages routes preserve the protocol; other routes may translate it or reject an unsupported dialect. Inference is charged against the organization's budget.",
  "x-orkestera-surface": {
    "service": "client_edge",
    "status": "live",
    "issue": null,
    "gate": "inference:write",
    "audience": "client_edge"
  },
  "x-orkestera-errors": [
    "dialect_mismatch",
    "invalid_token",
    "insufficient_scope",
    "client_identity_required",
    "posture_not_permitted",
    "rate_limited",
    "upstream_unavailable",
    "budget_exceeded",
    "model_not_available",
    "route_unavailable",
    "invalid_request",
    "upstream_rejected",
    "upstream_rate_limited"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://edge.orkestera.test"
        }
      },
      "description": "The Client Edge; location and host decided by."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "inference:write"
      ]
    },
    {
      "clientIngestCredential": []
    },
    {
      "clientApiKey": []
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "model",
            "messages",
            "max_tokens"
          ],
          "description": "Anthropic Messages request, unchanged."
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/MessagesOrUpstreamError"
    },
    "401": {
      "$ref": "#/components/responses/MessagesError"
    },
    "402": {
      "$ref": "#/components/responses/MessagesOrUpstreamError"
    },
    "403": {
      "$ref": "#/components/responses/MessagesError"
    },
    "404": {
      "$ref": "#/components/responses/MessagesOrUpstreamError"
    },
    "413": {
      "$ref": "#/components/responses/MessagesOrUpstreamError"
    },
    "429": {
      "description": "The Edge's rate_limited (a Client Ingest Credential exchanged too often), or llmproxy's upstream_rate_limited, which carries the provider's Retry-After. Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since  both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.",
      "x-orkestera-error-dialect": "anthropic",
      "headers": {
        "Retry-After": {
          "description": "Present on llmproxy's upstream_rate_limited; the Edge's own rate_limited sets none.",
          "required": false,
          "schema": {
            "type": "string"
          }
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/edge-error.schema.json#/$defs/anthropic"
          }
        }
      }
    },
    "502": {
      "$ref": "#/components/responses/MessagesOrUpstreamError"
    },
    "503": {
      "$ref": "#/components/responses/MessagesOrUpstreamError"
    }
  }
}

Error codes: dialect_mismatch, invalid_token, insufficient_scope, client_identity_required, posture_not_permitted, rate_limited, upstream_unavailable, budget_exceeded, model_not_available, route_unavailable, invalid_request, upstream_rejected, upstream_rate_limited

Report usage bought beside Orkestera

Audience: client_edge · inference:write · Edge alternative: inference-purpose Client Ingest Credential

Report inference purchased directly from another provider. Usage is attributed to the authenticated principal, recorded as reported and not debited against Orkestera's inference budget. The body limit is 64 KiB; oversized reports currently return 502 upstream_unavailable.

Request schema · application/json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Reported usage",
  "description": "`POST /v1/usage` at the Client Edge : inference a client bought from a provider directly, reported with the same token it would call the Edge with. The Edge caps the body at 64 KiB and forwards it to llmproxy's `/v1/client/usage`, which records it as `usage_source: reported` under the token's org, client and user. It is never debited, never counted as a request llmproxy served and never priced as Orkestera spend. Org, client, user and posture come from the token; a body field naming them is ignored like any other unknown field.",
  "type": "object",
  "required": [
    "model"
  ],
  "properties": {
    "model": {
      "description": "Trimmed of surrounding whitespace, then 1 to 256 bytes.",
      "type": "string",
      "minLength": 1,
      "maxLength": 256,
      "pattern": "\\S"
    },
    "provider": {
      "description": "The provider the client called, as the client names it.",
      "type": "string"
    },
    "prompt_tokens": {
      "description": "Absent or null is not reported, and is stored absent, never as zero.",
      "type": [
        "integer",
        "null"
      ],
      "minimum": 0
    },
    "completion_tokens": {
      "description": "Absent or null is not reported, and is stored absent, never as zero.",
      "type": [
        "integer",
        "null"
      ],
      "minimum": 0
    },
    "total_tokens": {
      "description": "Absent or 0 means prompt_tokens + completion_tokens.",
      "type": "integer",
      "minimum": 0
    },
    "duration_ms": {
      "type": "integer",
      "minimum": 0
    }
  }
}
Responses
StatusMeaning
202Recorded, not debited.
400Client Edge error: the stable code is `error.code`.
401Client Edge error: the stable code is `error.code`.
403Client Edge error: the stable code is `error.code`.
429Client Edge error: the stable code is `error.code`.
500llmproxy could not store the report; nothing was recorded. Its `storage_unavailable`, in the Edge dialect.
502Client Edge error: the stable code is `error.code`.
503Client Edge error: the stable code is `error.code`.
Full operation contract
{
  "summary": "Report usage bought beside Orkestera",
  "description": "Report inference purchased directly from another provider. Usage is attributed to the authenticated principal, recorded as reported and not debited against Orkestera's inference budget. The body limit is 64 KiB; oversized reports currently return 502 upstream_unavailable.",
  "x-orkestera-surface": {
    "service": "client_edge",
    "status": "live",
    "issue": null,
    "gate": "inference:write",
    "audience": "client_edge"
  },
  "x-orkestera-errors": [
    "invalid_usage_report",
    "invalid_token",
    "insufficient_scope",
    "client_identity_required",
    "posture_not_permitted",
    "rate_limited",
    "upstream_unavailable",
    "storage_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://edge.orkestera.test"
        }
      },
      "description": "The Client Edge; location and host decided by."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "inference:write"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "./schemas/usage-report.schema.json"
        }
      }
    }
  },
  "responses": {
    "202": {
      "description": "Recorded, not debited.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/usage-response.schema.json"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/EdgeError"
    },
    "401": {
      "$ref": "#/components/responses/EdgeError"
    },
    "403": {
      "$ref": "#/components/responses/EdgeError"
    },
    "429": {
      "$ref": "#/components/responses/EdgeError"
    },
    "500": {
      "description": "llmproxy could not store the report; nothing was recorded. Its `storage_unavailable`, in the Edge dialect.",
      "x-orkestera-error-dialect": "edge",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/edge-error.schema.json#/$defs/edge"
          }
        }
      }
    },
    "502": {
      "$ref": "#/components/responses/EdgeError"
    },
    "503": {
      "$ref": "#/components/responses/EdgeError"
    }
  }
}

Error codes: invalid_usage_report, invalid_token, insufficient_scope, client_identity_required, posture_not_permitted, rate_limited, upstream_unavailable, storage_unavailable

Native Responses with full tool payloads (JSON or SSE)

Audience: client_edge · inference:write · Edge alternative: inference-purpose Client Ingest Credential

Send a native Responses request on an explicitly pinned Responses route. Tool definitions, calls, results and reasoning items pass through without translation or client-specific filtering. Use stateless input replay with store:false; stored conversation references and background jobs are refused. JSON and SSE are supported. Inference uses the organization’s budget, and the route does not switch providers or models during a continuation.

Request schema · application/json
{
  "type": "object",
  "required": [
    "model",
    "input"
  ],
  "properties": {
    "model": {
      "type": "string"
    },
    "input": {},
    "stream": {
      "type": "boolean"
    },
    "store": {
      "type": "boolean",
      "enum": [
        false
      ]
    },
    "background": {
      "type": "boolean",
      "enum": [
        false
      ]
    }
  },
  "additionalProperties": true,
  "description": "Native tool/content fields are preserved. Select a responses-dialect model route."
}
Responses
StatusMeaning
200OK
400Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
401Client Edge error: the stable code is `error.code`.
402Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
403Client Edge error: the stable code is `error.code`.
404Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
429Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
502Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
503Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
413Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
Full operation contract
{
  "summary": "Native Responses with full tool payloads (JSON or SSE)",
  "description": "Send a native Responses request on an explicitly pinned Responses route. Tool definitions, calls, results and reasoning items pass through without translation or client-specific filtering. Use stateless input replay with store:false; stored conversation references and background jobs are refused. JSON and SSE are supported. Inference uses the organization\u2019s budget, and the route does not switch providers or models during a continuation.",
  "x-orkestera-surface": {
    "service": "client_edge",
    "status": "live",
    "issue": null,
    "gate": "inference:write",
    "audience": "client_edge"
  },
  "x-orkestera-errors": [
    "dialect_mismatch",
    "invalid_token",
    "insufficient_scope",
    "client_identity_required",
    "posture_not_permitted",
    "rate_limited",
    "upstream_unavailable",
    "budget_exceeded",
    "model_not_available",
    "route_unavailable",
    "invalid_request",
    "upstream_rejected",
    "upstream_rate_limited",
    "request_too_large"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://edge.orkestera.test"
        }
      },
      "description": "The Client Edge; location and host decided by."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "inference:write"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "model",
            "input"
          ],
          "properties": {
            "model": {
              "type": "string"
            },
            "input": {},
            "stream": {
              "type": "boolean"
            },
            "store": {
              "type": "boolean",
              "enum": [
                false
              ]
            },
            "background": {
              "type": "boolean",
              "enum": [
                false
              ]
            }
          },
          "additionalProperties": true,
          "description": "Native tool/content fields are preserved. Select a responses-dialect model route."
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        },
        "text/event-stream": {
          "schema": {
            "type": "string",
            "description": "Native Responses SSE events, including tool/continuation payloads and terminal usage."
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "401": {
      "$ref": "#/components/responses/EdgeError"
    },
    "402": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "403": {
      "$ref": "#/components/responses/EdgeError"
    },
    "404": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "429": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "502": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "503": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "413": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    }
  }
}

Error codes: dialect_mismatch, invalid_token, insufficient_scope, client_identity_required, posture_not_permitted, rate_limited, upstream_unavailable, budget_exceeded, model_not_available, route_unavailable, invalid_request, upstream_rejected, upstream_rate_limited, request_too_large

Compact native Responses history

Audience: client_edge · inference:write · Edge alternative: inference-purpose Client Ingest Credential

Compact native Responses history on the same pinned provider/model route. The result is a response.compaction JSON object for later input replay. Streaming, stored histories and background work are not supported on this endpoint. Full native content and tool payloads are preserved.

Request schema · application/json
{
  "type": "object",
  "required": [
    "model",
    "input"
  ],
  "properties": {
    "model": {
      "type": "string"
    },
    "input": {},
    "stream": {
      "type": "boolean",
      "enum": [
        false
      ]
    },
    "store": {
      "type": "boolean",
      "enum": [
        false
      ]
    },
    "background": {
      "type": "boolean",
      "enum": [
        false
      ]
    }
  },
  "additionalProperties": true,
  "description": "Native tool/content fields are preserved. Select a responses-dialect model route."
}
Responses
StatusMeaning
200OK
400Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
401Client Edge error: the stable code is `error.code`.
402Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
403Client Edge error: the stable code is `error.code`.
404Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
429Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
502Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
503Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
413Two writers answer here: the Client Edge, and llmproxy, whose refusals the Edge relays byte for byte (it intercepts only an upstream 401). Since both write this one dialect at `application/json`, with a stable code from errors.json. Branch on the code.
Full operation contract
{
  "summary": "Compact native Responses history",
  "description": "Compact native Responses history on the same pinned provider/model route. The result is a response.compaction JSON object for later input replay. Streaming, stored histories and background work are not supported on this endpoint. Full native content and tool payloads are preserved.",
  "x-orkestera-surface": {
    "service": "client_edge",
    "status": "live",
    "issue": null,
    "gate": "inference:write",
    "audience": "client_edge"
  },
  "x-orkestera-errors": [
    "dialect_mismatch",
    "invalid_token",
    "insufficient_scope",
    "client_identity_required",
    "posture_not_permitted",
    "rate_limited",
    "upstream_unavailable",
    "budget_exceeded",
    "model_not_available",
    "route_unavailable",
    "invalid_request",
    "upstream_rejected",
    "upstream_rate_limited",
    "request_too_large"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://edge.orkestera.test"
        }
      },
      "description": "The Client Edge; location and host decided by."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "inference:write"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "model",
            "input"
          ],
          "properties": {
            "model": {
              "type": "string"
            },
            "input": {},
            "stream": {
              "type": "boolean",
              "enum": [
                false
              ]
            },
            "store": {
              "type": "boolean",
              "enum": [
                false
              ]
            },
            "background": {
              "type": "boolean",
              "enum": [
                false
              ]
            }
          },
          "additionalProperties": true,
          "description": "Native tool/content fields are preserved. Select a responses-dialect model route."
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "401": {
      "$ref": "#/components/responses/EdgeError"
    },
    "402": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "403": {
      "$ref": "#/components/responses/EdgeError"
    },
    "404": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "429": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "502": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "503": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    },
    "413": {
      "$ref": "#/components/responses/EdgeOrUpstreamError"
    }
  }
}

Error codes: dialect_mismatch, invalid_token, insufficient_scope, client_identity_required, posture_not_permitted, rate_limited, upstream_unavailable, budget_exceeded, model_not_available, route_unavailable, invalid_request, upstream_rejected, upstream_rate_limited, request_too_large

Tasks & progress

List the org's tasks (governed work), a page at a time

Audience: platform · tasks:read

List organization-owned tasks, newest first. Filter by comma-separated status and page with limit and cursor. The X-Next-Cursor response header identifies the next page. Keep the same filters when reusing a cursor. Storage failure returns 503 rather than an empty list.

Parameters
NameLocationRequiredDescription
limitqueryOptionalRows per page.
statusqueryOptionalComma-separated task statuses (contracts/task_statuses.golden.json); only tasks in one of them are listed.
cursorqueryOptionalThe previous page's `X-Next-Cursor`. Opaque.
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
503A stable code; the response carries Retry-After.
Full operation contract
{
  "summary": "List the org's tasks (governed work), a page at a time",
  "description": "List organization-owned tasks, newest first. Filter by comma-separated status and page with limit and cursor. The X-Next-Cursor response header identifies the next page. Keep the same filters when reusing a cursor. Storage failure returns 503 rather than an empty list.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:read",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "invalid_request",
    "invalid_cursor",
    "org_required",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:read"
      ]
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "headers": {
        "X-Next-Cursor": {
          "schema": {
            "type": "string"
          },
          "description": "Present when another page follows; pass it back as `cursor`."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Task"
            }
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "description": "A stable code; the response carries Retry-After.",
      "headers": {
        "Retry-After": {
          "schema": {
            "type": "integer"
          },
          "description": "Seconds to wait before retrying."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/error.schema.json"
          }
        }
      }
    }
  },
  "parameters": [
    {
      "name": "limit",
      "in": "query",
      "required": false,
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 100,
        "default": 100
      },
      "description": "Rows per page."
    },
    {
      "name": "status",
      "in": "query",
      "required": false,
      "schema": {
        "type": "string"
      },
      "description": "Comma-separated task statuses (contracts/task_statuses.golden.json); only tasks in one of them are listed."
    },
    {
      "name": "cursor",
      "in": "query",
      "required": false,
      "schema": {
        "type": "string"
      },
      "description": "The previous page's `X-Next-Cursor`. Opaque."
    }
  ]
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, invalid_request, invalid_cursor, org_required, temporarily_unavailable

Submit a goal as a Task

Audience: platform · tasks:write

Submit a goal for governed execution. The response identifies the task and its initial status. The organization comes from the token; policy escape flags are refused.

Request schema · application/json
{
  "type": "object",
  "required": [
    "goal"
  ],
  "properties": {
    "goal": {
      "type": "string",
      "minLength": 1
    }
  }
}
Responses
StatusMeaning
201OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
422Error with a stable code.
503A stable code; the response carries Retry-After.
Full operation contract
{
  "summary": "Submit a goal as a Task",
  "description": "Submit a goal for governed execution. The response identifies the task and its initial status. The organization comes from the token; policy escape flags are refused.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:write",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "escape_flag_refused",
    "invalid_request",
    "task_not_created",
    "org_required",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:write"
      ]
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "goal"
          ],
          "properties": {
            "goal": {
              "type": "string",
              "minLength": 1
            }
          }
        }
      }
    }
  },
  "responses": {
    "201": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "required": [
              "task_id",
              "status"
            ],
            "properties": {
              "task_id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "422": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "description": "A stable code; the response carries Retry-After.",
      "headers": {
        "Retry-After": {
          "schema": {
            "type": "integer"
          },
          "description": "Seconds to wait before retrying."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/error.schema.json"
          }
        }
      }
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, escape_flag_refused, invalid_request, task_not_created, org_required, temporarily_unavailable

One task's detail

Audience: platform · tasks:read

Read task status, issues and available results. Artifact URLs are temporary signed links; re-read the task when they expire. Missing tasks and tasks outside the caller's organization both return task_not_found.

Parameters
NameLocationRequiredDescription
task_idpathRequiredTask id.
Responses
StatusMeaning
200OK
401Error with a stable code.
403Error with a stable code.
404Error with a stable code.
503A stable code; the response carries Retry-After.
Full operation contract
{
  "summary": "One task's detail",
  "description": "Read task status, issues and available results. Artifact URLs are temporary signed links; re-read the task when they expire. Missing tasks and tasks outside the caller's organization both return task_not_found.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:read",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "org_required",
    "task_not_found",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:read"
      ]
    }
  ],
  "parameters": [
    {
      "name": "task_id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "Task id."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/TaskDetail"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "404": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "description": "A stable code; the response carries Retry-After.",
      "headers": {
        "Retry-After": {
          "schema": {
            "type": "integer"
          },
          "description": "Seconds to wait before retrying."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/error.schema.json"
          }
        }
      }
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, org_required, task_not_found, temporarily_unavailable

Delete a task that is not running

Audience: platform · tasks:write

Delete an organization-owned task that is not running. A running task returns task_status_conflict. Deleting a task is distinct from halting its execution.

Parameters
NameLocationRequiredDescription
task_idpathRequiredTask id.
Responses
StatusMeaning
200OK
401Error with a stable code.
403Error with a stable code.
404Error with a stable code.
409Error with a stable code.
500Error with a stable code.
Full operation contract
{
  "summary": "Delete a task that is not running",
  "description": "Delete an organization-owned task that is not running. A running task returns task_status_conflict. Deleting a task is distinct from halting its execution.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:write",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "task_not_found",
    "task_status_conflict",
    "internal_error"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:write"
      ]
    }
  ],
  "parameters": [
    {
      "name": "task_id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "Task id."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "required": [
              "task_id",
              "status"
            ],
            "properties": {
              "task_id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "404": {
      "$ref": "#/components/responses/Error"
    },
    "409": {
      "$ref": "#/components/responses/Error"
    },
    "500": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, task_not_found, task_status_conflict, internal_error

Start a planned task

Audience: platform · tasks:write

Start a planned task. The response reports planning; policy escape flags are refused. Check status after any ambiguous transport failure before repeating the request.

Parameters
NameLocationRequiredDescription
task_idpathRequiredTask id.
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
404Error with a stable code.
409Error with a stable code.
503A stable code; the response carries Retry-After.
Full operation contract
{
  "summary": "Start a planned task",
  "description": "Start a planned task. The response reports planning; policy escape flags are refused. Check status after any ambiguous transport failure before repeating the request.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:write",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "escape_flag_refused",
    "task_not_found",
    "task_status_conflict",
    "platform_halted",
    "task_already_dispatched",
    "runner_unavailable",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:write"
      ]
    }
  ],
  "parameters": [
    {
      "name": "task_id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "Task id."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "required": [
              "task_id",
              "status"
            ],
            "properties": {
              "task_id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "404": {
      "$ref": "#/components/responses/Error"
    },
    "409": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "description": "A stable code; the response carries Retry-After.",
      "headers": {
        "Retry-After": {
          "schema": {
            "type": "integer"
          },
          "description": "Seconds to wait before retrying."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/error.schema.json"
          }
        }
      }
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, escape_flag_refused, task_not_found, task_status_conflict, platform_halted, task_already_dispatched, runner_unavailable, temporarily_unavailable

Halt one unfinished task

Audience: platform · tasks:write

Stop one unfinished task and mark it halted. A finished task returns task_status_conflict. A failed state write returns 503 without announcing a successful halt.

Parameters
NameLocationRequiredDescription
task_idpathRequiredTask id.
Responses
StatusMeaning
200OK
401Error with a stable code.
403Error with a stable code.
404Error with a stable code.
409Error with a stable code.
503A stable code; the response carries Retry-After.
Full operation contract
{
  "summary": "Halt one unfinished task",
  "description": "Stop one unfinished task and mark it halted. A finished task returns task_status_conflict. A failed state write returns 503 without announcing a successful halt.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:write",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "org_required",
    "task_not_found",
    "task_status_conflict",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:write"
      ]
    }
  ],
  "parameters": [
    {
      "name": "task_id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "Task id."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "required": [
              "task_id",
              "status"
            ],
            "properties": {
              "task_id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "404": {
      "$ref": "#/components/responses/Error"
    },
    "409": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "description": "A stable code; the response carries Retry-After.",
      "headers": {
        "Retry-After": {
          "schema": {
            "type": "integer"
          },
          "description": "Seconds to wait before retrying."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/error.schema.json"
          }
        }
      }
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, org_required, task_not_found, task_status_conflict, temporarily_unavailable

Resume a halted, failed or pending task

Audience: platform · tasks:write

Re-dispatch a halted, failed or pending task. The response reports planning. Organization ownership and policy escape-flag checks still apply.

Parameters
NameLocationRequiredDescription
task_idpathRequiredTask id.
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
404Error with a stable code.
409Error with a stable code.
503A stable code; the response carries Retry-After.
Full operation contract
{
  "summary": "Resume a halted, failed or pending task",
  "description": "Re-dispatch a halted, failed or pending task. The response reports planning. Organization ownership and policy escape-flag checks still apply.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": "tasks:write",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "escape_flag_refused",
    "org_required",
    "task_not_found",
    "task_status_conflict",
    "platform_halted",
    "task_already_dispatched",
    "runner_unavailable",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:write"
      ]
    }
  ],
  "parameters": [
    {
      "name": "task_id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "Task id."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object",
            "required": [
              "task_id",
              "status"
            ],
            "properties": {
              "task_id": {
                "type": "string"
              },
              "status": {
                "type": "string"
              }
            }
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "404": {
      "$ref": "#/components/responses/Error"
    },
    "409": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "description": "A stable code; the response carries Retry-After.",
      "headers": {
        "Retry-After": {
          "schema": {
            "type": "integer"
          },
          "description": "Seconds to wait before retrying."
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/error.schema.json"
          }
        }
      }
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, escape_flag_refused, org_required, task_not_found, task_status_conflict, platform_halted, task_already_dispatched, runner_unavailable, temporarily_unavailable

Server-sent task progress events

Audience: platform · tasks:read or tasks:write

Subscribe to your organization's task progress with tasks:read or tasks:write. Save event IDs and reconnect with Last-Event-ID. When replay is unavailable the stream emits stream_reset; re-read the tasks you follow. IDs represent stream positions, not a count of your own events.

Parameters
NameLocationRequiredDescription
Last-Event-IDheaderOptionalThe `id:` of the last event received, sent on reconnect.
Responses
StatusMeaning
200text/event-stream
401Error with a stable code.
403Error with a stable code.
Full operation contract
{
  "summary": "Server-sent task progress events",
  "description": "Subscribe to your organization's task progress with tasks:read or tasks:write. Save event IDs and reconnect with Last-Event-ID. When replay is unavailable the stream emits stream_reset; re-read the tasks you follow. IDs represent stream positions, not a count of your own events.",
  "x-orkestera-surface": {
    "service": "platform",
    "status": "live",
    "issue": null,
    "gate": ":any_authenticated",
    "audience": "platform"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://platform.orkestera.test"
        }
      },
      "description": "Platform: the Task API (governed work)."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "tasks:read"
      ]
    },
    {
      "serviceToken": [
        "tasks:write"
      ]
    }
  ],
  "responses": {
    "200": {
      "description": "text/event-stream",
      "content": {
        "text/event-stream": {
          "schema": {
            "type": "string"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    }
  },
  "parameters": [
    {
      "name": "Last-Event-ID",
      "in": "header",
      "required": false,
      "schema": {
        "type": "string"
      },
      "description": "The `id:` of the last event received, sent on reconnect."
    }
  ]
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected

Telemetry & read-back

Ingest a batch of client.* events

Audience: watch · client:ingest

Ingest client.* event batches under the token's organization, client and user. Requires client_enforced or observed posture. Event IDs make retries idempotent. Sequenced state updates require consecutive sequence numbers; gaps request a snapshot. Merge events carry partial unsequenced state. Inspect each event result, including accepted events marked truncated. Reported policy drift is recorded; it does not block work.

Request schema · application/json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "client.* ingest batch",
  "description": "Body of POST /client/v1/events. Each event is validated on its own: one bad event is rejected in the response and does not fail the batch. Events are applied in array order.",
  "type": "object",
  "required": [
    "events"
  ],
  "properties": {
    "events": {
      "type": "array",
      "minItems": 1,
      "maxItems": 500,
      "items": {
        "oneOf": [
          {
            "$ref": "events/client.run.schema.json"
          },
          {
            "$ref": "events/client.task.schema.json"
          },
          {
            "$ref": "events/client.inference.schema.json"
          },
          {
            "$ref": "events/client.tool.schema.json"
          },
          {
            "$ref": "events/client.risk_posture.schema.json"
          },
          {
            "$ref": "events/client.lifecycle.schema.json"
          }
        ]
      }
    }
  },
  "additionalProperties": false
}
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
413Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "Ingest a batch of client.* events",
  "description": "Ingest client.* event batches under the token's organization, client and user. Requires client_enforced or observed posture. Event IDs make retries idempotent. Sequenced state updates require consecutive sequence numbers; gaps request a snapshot. Merge events carry partial unsequenced state. Inspect each event result, including accepted events marked truncated. Reported policy drift is recorded; it does not block work.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "client:ingest",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "posture_governed",
    "invalid_batch",
    "batch_too_large",
    "invalid_event",
    "event_id_conflict",
    "run_id_mismatch",
    "run_not_writable",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "client:ingest"
      ]
    }
  ],
  "requestBody": {
    "required": true,
    "content": {
      "application/json": {
        "schema": {
          "$ref": "./schemas/ingest-batch.schema.json"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "./schemas/ingest-response.schema.json"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "413": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, posture_governed, invalid_batch, batch_too_large, invalid_event, event_id_conflict, run_id_mismatch, run_not_writable, temporarily_unavailable

Ingest an OTLP/HTTP logs export

Audience: watch · client:ingest · Edge alternative: telemetry-purpose Client Ingest Credential

Ingest OTLP/HTTP logs as JSON or protobuf. At Watch, use a watch/client:ingest Service Token. At Client Edge, use a dedicated telemetry-purpose Client Ingest Credential; inference credentials and direct Service Tokens are refused there. Discover edge_otlp_logs for the Edge URL. Identity comes from verified claims. Raw log bodies and unsafe attributes are omitted. Inspect partialSuccess.rejectedLogRecords and honor Retry-After on 429. Edge bounds identity/gzip input and expanded data to 8 MiB; Watch retains its own record limits. No gRPC or traces endpoint is served.

Request schema · application/x-protobuf
{
  "type": "string",
  "format": "binary"
}
Request schema · application/json
{
  "type": "object"
}
Responses
StatusMeaning
200Accepted. The body is OTLP's own export response in the encoding the request used: empty on full success, and otherwise a partial success naming how many records were not accepted and why.
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
413Error with a stable code.
415Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "Ingest an OTLP/HTTP logs export",
  "description": "Ingest OTLP/HTTP logs as JSON or protobuf. At Watch, use a watch/client:ingest Service Token. At Client Edge, use a dedicated telemetry-purpose Client Ingest Credential; inference credentials and direct Service Tokens are refused there. Discover edge_otlp_logs for the Edge URL. Identity comes from verified claims. Raw log bodies and unsafe attributes are omitted. Inspect partialSuccess.rejectedLogRecords and honor Retry-After on 429. Edge bounds identity/gzip input and expanded data to 8 MiB; Watch retains its own record limits. No gRPC or traces endpoint is served.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "client:ingest",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "posture_governed",
    "invalid_batch",
    "unsupported_media_type",
    "batch_too_large",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    },
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://api.orkestera.test"
        }
      },
      "description": "Client Edge: telemetry-purpose credential only."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "client:ingest"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "requestBody": {
    "required": true,
    "description": "An OTLP ExportLogsServiceRequest (opentelemetry-proto v1), protobuf-encoded as application/x-protobuf or JSON-encoded as application/json. Any other Content-Type is unsupported_media_type.",
    "content": {
      "application/x-protobuf": {
        "schema": {
          "type": "string",
          "format": "binary"
        }
      },
      "application/json": {
        "schema": {
          "type": "object"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Accepted. The body is OTLP's own export response in the encoding the request used: empty on full success, and otherwise a partial success naming how many records were not accepted and why.",
      "content": {
        "application/x-protobuf": {
          "schema": {
            "type": "string",
            "format": "binary"
          }
        },
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "partialSuccess": {
                "type": "object",
                "required": [
                  "rejectedLogRecords",
                  "errorMessage"
                ],
                "properties": {
                  "rejectedLogRecords": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "errorMessage": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              }
            },
            "additionalProperties": false
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "413": {
      "$ref": "#/components/responses/Error"
    },
    "415": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  },
  "x-orkestera-edge-credential-purpose": "telemetry"
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, posture_governed, invalid_batch, unsupported_media_type, batch_too_large, temporarily_unavailable

Ingest an OTLP/HTTP metrics export

Audience: watch · client:ingest · Edge alternative: telemetry-purpose Client Ingest Credential

Ingest OTLP/HTTP metrics as JSON or protobuf. Watch accepts a watch/client:ingest Service Token; Client Edge accepts only a telemetry-purpose Client Ingest Credential at the discovered edge_otlp_metrics URL. Cumulative sums and gauges report running totals per series; delta sums are not accumulated across exports. The resulting run is unsequenced and does not claim complete history. Inspect partial-success responses. Codex’s generated profile disables metrics and uses logs only.

Request schema · application/x-protobuf
{
  "type": "string",
  "format": "binary"
}
Request schema · application/json
{
  "type": "object"
}
Responses
StatusMeaning
200Accepted. The body is OTLP's own export response in the encoding the request used: empty on full success, and otherwise a partial success naming how many records were not accepted and why.
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
413Error with a stable code.
415Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "Ingest an OTLP/HTTP metrics export",
  "description": "Ingest OTLP/HTTP metrics as JSON or protobuf. Watch accepts a watch/client:ingest Service Token; Client Edge accepts only a telemetry-purpose Client Ingest Credential at the discovered edge_otlp_metrics URL. Cumulative sums and gauges report running totals per series; delta sums are not accumulated across exports. The resulting run is unsequenced and does not claim complete history. Inspect partial-success responses. Codex\u2019s generated profile disables metrics and uses logs only.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "client:ingest",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "posture_governed",
    "invalid_batch",
    "unsupported_media_type",
    "batch_too_large",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    },
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://api.orkestera.test"
        }
      },
      "description": "Client Edge: telemetry-purpose credential only."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "client:ingest"
      ]
    },
    {
      "clientIngestCredential": []
    }
  ],
  "requestBody": {
    "required": true,
    "description": "An OTLP ExportMetricsServiceRequest (opentelemetry-proto v1), protobuf-encoded as application/x-protobuf or JSON-encoded as application/json. Any other Content-Type is unsupported_media_type.",
    "content": {
      "application/x-protobuf": {
        "schema": {
          "type": "string",
          "format": "binary"
        }
      },
      "application/json": {
        "schema": {
          "type": "object"
        }
      }
    }
  },
  "responses": {
    "200": {
      "description": "Accepted. The body is OTLP's own export response in the encoding the request used: empty on full success, and otherwise a partial success naming how many records were not accepted and why.",
      "content": {
        "application/x-protobuf": {
          "schema": {
            "type": "string",
            "format": "binary"
          }
        },
        "application/json": {
          "schema": {
            "type": "object",
            "properties": {
              "partialSuccess": {
                "type": "object",
                "required": [
                  "rejectedDataPoints",
                  "errorMessage"
                ],
                "properties": {
                  "rejectedDataPoints": {
                    "type": "integer",
                    "minimum": 1
                  },
                  "errorMessage": {
                    "type": "string"
                  }
                },
                "additionalProperties": false
              }
            },
            "additionalProperties": false
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "413": {
      "$ref": "#/components/responses/Error"
    },
    "415": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  },
  "x-orkestera-edge-credential-purpose": "telemetry"
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, posture_governed, invalid_batch, unsupported_media_type, batch_too_large, temporarily_unavailable

List the org's external runs

Audience: watch · watch:read

Page through the organization's external runs, newest first by creation. Updates do not move runs between pages. Use the returned cursor; invalid cursors are rejected. Optional filters narrow the current organization only.

Parameters
NameLocationRequiredDescription
session_idqueryOptional
client_idqueryOptionalOnly runs this client registration reported.
client_kindqueryOptional
limitqueryOptional
cursorqueryOptional
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "List the org's external runs",
  "description": "Page through the organization's external runs, newest first by creation. Updates do not move runs between pages. Use the returned cursor; invalid cursors are rejected. Optional filters narrow the current organization only.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "watch:read",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "temporarily_unavailable",
    "invalid_cursor"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "watch:read"
      ]
    }
  ],
  "parameters": [
    {
      "name": "session_id",
      "in": "query",
      "schema": {
        "type": "string"
      }
    },
    {
      "name": "client_id",
      "in": "query",
      "schema": {
        "type": "string"
      },
      "description": "Only runs this client registration reported."
    },
    {
      "name": "client_kind",
      "in": "query",
      "schema": {
        "type": "string"
      }
    },
    {
      "name": "limit",
      "in": "query",
      "schema": {
        "type": "integer",
        "minimum": 1,
        "maximum": 500
      }
    },
    {
      "name": "cursor",
      "in": "query",
      "schema": {
        "type": "string"
      }
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/RunList"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, temporarily_unavailable, invalid_cursor

One external run's summary

Audience: watch · watch:read

Read reduced run state, attribution and reporting status. Client-chosen run IDs may collide; narrow the lookup with client_id and session_id. Ambiguous matches return run_ambiguous. Runs outside the organization return run_not_found.

Parameters
NameLocationRequiredDescription
run_idpathRequiredThe client's run id.
client_idqueryOptionalThe client registration that reported the run.
session_idqueryOptionalThe session the run was reported in.
Responses
StatusMeaning
200OK
401Error with a stable code.
403Error with a stable code.
404Error with a stable code.
409Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "One external run's summary",
  "description": "Read reduced run state, attribution and reporting status. Client-chosen run IDs may collide; narrow the lookup with client_id and session_id. Ambiguous matches return run_ambiguous. Runs outside the organization return run_not_found.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "watch:read",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "run_not_found",
    "run_ambiguous",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "watch:read"
      ]
    }
  ],
  "parameters": [
    {
      "name": "run_id",
      "in": "path",
      "required": true,
      "schema": {
        "type": "string"
      },
      "description": "The client's run id."
    },
    {
      "name": "client_id",
      "in": "query",
      "schema": {
        "type": "string"
      },
      "description": "The client registration that reported the run."
    },
    {
      "name": "session_id",
      "in": "query",
      "schema": {
        "type": "string"
      },
      "description": "The session the run was reported in."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/RunSummary"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "404": {
      "$ref": "#/components/responses/Error"
    },
    "409": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, run_not_found, run_ambiguous, temporarily_unavailable

Cross-client analysis for the org

Audience: watch · watch:read

Analyze external and governed runs by client kind, harness, model, posture or user within retained history. Figures are available, partial or unavailable. A partial value is a lower bound; absent data is never reported as zero. Inspect the sources and window metadata before comparing totals.

Parameters
NameLocationRequiredDescription
group_byqueryOptionalThe one breakdown to answer. Absent: all five.
sincequeryOptionalRFC 3339 with an offset; runs that started at or after it. Earlier than Watch's retention window is clamped to the window's start. In the future is invalid_request.
user_idqueryOptionalOnly runs this user of the token's org started. A user of another org matches nothing.
Responses
StatusMeaning
200OK
400Error with a stable code.
401Error with a stable code.
403Error with a stable code.
503Error with a stable code.
Full operation contract
{
  "summary": "Cross-client analysis for the org",
  "description": "Analyze external and governed runs by client kind, harness, model, posture or user within retained history. Figures are available, partial or unavailable. A partial value is a lower bound; absent data is never reported as zero. Inspect the sources and window metadata before comparing totals.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "watch:read",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected",
    "org_required",
    "invalid_request",
    "temporarily_unavailable"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "watch:read"
      ]
    }
  ],
  "parameters": [
    {
      "name": "group_by",
      "in": "query",
      "schema": {
        "type": "string",
        "enum": [
          "client_kind",
          "harness",
          "model",
          "posture",
          "user"
        ]
      },
      "description": "The one breakdown to answer. Absent: all five."
    },
    {
      "name": "since",
      "in": "query",
      "schema": {
        "type": "string",
        "format": "date-time"
      },
      "description": "RFC 3339 with an offset; runs that started at or after it. Earlier than Watch's retention window is clamped to the window's start. In the future is invalid_request."
    },
    {
      "name": "user_id",
      "in": "query",
      "schema": {
        "type": "string",
        "minLength": 1
      },
      "description": "Only runs this user of the token's org started. A user of another org matches nothing."
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/AnalysisReport"
          }
        }
      }
    },
    "400": {
      "$ref": "#/components/responses/Error"
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    },
    "503": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected, org_required, invalid_request, temporarily_unavailable

Inference statistics: fleet aggregates and organization-owned slices

Audience: watch · watch:read

Read an operational inference snapshot with mixed coverage. by_task and by_agent use the token’s organization-owned slices; by_model, totals and latency are fleet aggregates with no tenant key. Older snapshots without owned splits return empty tenant maps. Distinguish lifetime counters from rolling-window metrics and inspect availability. Fleet totals are not your organization’s billed spend; use its entitled Spend views for organization usage estimates.

Responses
StatusMeaning
200OK
401Error with a stable code.
403Error with a stable code.
Full operation contract
{
  "summary": "Inference statistics: fleet aggregates and organization-owned slices",
  "description": "Read an operational inference snapshot with mixed coverage. by_task and by_agent use the token\u2019s organization-owned slices; by_model, totals and latency are fleet aggregates with no tenant key. Older snapshots without owned splits return empty tenant maps. Distinguish lifetime counters from rolling-window metrics and inspect availability. Fleet totals are not your organization\u2019s billed spend; use its entitled Spend views for organization usage estimates.",
  "x-orkestera-surface": {
    "service": "watch",
    "status": "live",
    "issue": null,
    "gate": "watch:read",
    "audience": "watch"
  },
  "x-orkestera-errors": [
    "unauthorized",
    "malformed",
    "untrusted_issuer",
    "unknown_key",
    "bad_signature",
    "expired",
    "not_yet_valid",
    "key_source_unavailable",
    "wrong_audience",
    "insufficient_scope",
    "policy_rejected"
  ],
  "servers": [
    {
      "url": "{base}",
      "variables": {
        "base": {
          "default": "https://watch.orkestera.test"
        }
      },
      "description": "Watch: client.* ingest and read-back."
    }
  ],
  "security": [
    {
      "serviceToken": [
        "watch:read"
      ]
    }
  ],
  "responses": {
    "200": {
      "description": "OK",
      "content": {
        "application/json": {
          "schema": {
            "type": "object"
          }
        }
      }
    },
    "401": {
      "$ref": "#/components/responses/Error"
    },
    "403": {
      "$ref": "#/components/responses/Error"
    }
  }
}

Error codes: unauthorized, malformed, untrusted_issuer, unknown_key, bad_signature, expired, not_yet_valid, key_source_unavailable, wrong_audience, insufficient_scope, policy_rejected

Published workflows

Use a Platform token with workflows:read to discover published revisions and follow runs. Starting or halting a run requires workflows:run. Run submission uses the approving user from the token; the user must remain an active organization member with permission to execute the workflow.

Workflow API · audience platform
MethodPathScope
GET/api/published_workflowsworkflows:read
GET/api/published_workflows/{id}workflows:read
POST/api/published_workflows/{id}/revisions/{revision}/runsworkflows:run
GET/api/workflow_runs/{task_id}workflows:read
GET/api/workflow_runs/{task_id}/eventsworkflows:read
POST/api/workflow_runs/{task_id}/haltworkflows:run

Submit a JSON body such as {"goal":"Review the checkout flow"} to a positive revision number. A successful submission returns 202 with a data wrapper; ordinary reads and halt return 200. Errors return {"error":"…"}: access denied (403), missing workflow (404), halted or finished run (409), invalid goal or non-executable revision (422), or unavailable storage (503). These routes are verified against the Platform router and controller and are not yet part of the downloadable Client Contract.

The status response includes task_id, run_id, status, the published revision digest, node states and evaluations, and the workflow result when available. Node progress reflects the events received; it is not a complete execution transcript. Failure reads expose a stage and safe headline rather than raw provider failure text.

Follow /api/workflow_runs/{task_id}/events with Accept: text/event-stream. Keep each event ID, reconnect with Last-Event-ID, and re-read run status on stream_reset. This stream is limited to that run in your organization. Halting an unfinished run returns its halted status; a finished run returns 409. After an ambiguous submission, inspect existing runs before retrying: there is no documented create-run idempotency key.

Errors & retries

Inspect both the HTTP status and the endpoint’s error code. Identity uses OAuth errors; Client Edge uses an OpenAI-style error object, and Messages uses an Anthropic-style error envelope. Workflow errors use a text error field. Do not assume a single error schema across services.

Recovery guidance
FailureWhat to do
401 · invalid_tokenRefresh or obtain a token for the correct audience; verify its expiry.
403 · insufficient_scope / posture_not_permittedCheck the registration’s grants and organization policy. Repeated retries will not add access.
402 · budget_exceededReview the organization’s inference budget before retrying.
429Honor Retry-After when present and back off with jitter.
503 · temporarily_unavailableRetry safe reads with backoff. Replay event batches with their original event IDs. Do not blindly repeat task creation or inference after an ambiguous failure.
snapshot_required / stream_resetSend a fresh run snapshot or re-read task state, respectively.