SOIT Docs
API Reference

Gateway, Tools, and MCP API

API surface for the OpenAI-compatible /v1 gateway, the Anthropic Messages API, direct tool calls, and the /mcp endpoint.

These endpoints are how code outside the SOIT console calls a workspace's models and tools. Every call is a governed run. For concepts and configuration, see OpenAI-Compatible Gateway and MCP Server. This page describes v1.3.0, with the changes in v1.4.0, v1.5.0, and v1.6.0 marked.

Prefixes

/v1              OpenAI-compatible gateway (since v1.2.0), and the Anthropic Messages API at /v1/messages (since v1.5.0)
/api/v1/tools    direct tool calls (since v1.3.0)
/mcp             MCP server (since v1.3.0)

New in v1.4.0: a process started with SOIT_ROLE=gateway serves only these prefixes, the /.well-known discovery metadata of /mcp, and /health and /metrics; every other path answers 404 there. See Running the gateway on its own.

Authentication

  • Send a SOIT API key as Authorization: Bearer sk_…. SOIT's API also accepts the key in X-API-Key, which is what the Anthropic SDKs send to /v1/messages.
  • The key's scopes (read, write, admin) cap what it may do below its owner's role; calling models and tools needs write. POST /v1/messages/count_tokens, which calls no model, needs read.
  • A signed-in session works too; over /mcp it names the workspace in X-Workspace-Id.
  • A key issued to a service principal authenticates as the principal.

/v1 endpoints

MethodPathNotes
POST/v1/chat/completionsWhole or streamed (stream, stream_options.include_usage). Tools and tool_choice, images in user messages, response_format (json_object, json_schema), temperature, top_p, max_tokens / max_completion_tokens, stop, seed. n must be 1.
POST/v1/messagesNew in v1.5.0: the Anthropic Messages API, whole or streamed in Anthropic's named events. model, max_tokens, messages, system, temperature, top_p, stop_sequences, stream, tools, tool_choice. See Anthropic Messages.
POST/v1/messages/count_tokensNew in v1.5.0: {"input_tokens": n} for a prompt. SOIT's estimate, not the provider's tokenizer; calls no model, opens no run, and is not billed.
GET/v1/modelsActive models and virtual models the key may call, by the ref a call names. From v1.5.0 each entry also carries Anthropic's type, display_name, and created_at, and the list has_more, first_id, and last_id.
POST/v1/embeddingsencoding_format float or base64 (the SDKs' default).
POST/v1/images/generationsn, size (64 to 4096 pixels a side, or auto), response_format. A size out of range is refused before the call is billed. New in v1.4.0: background, output_format (png, jpeg, webp), and quality.
POST/v1/images/editsMultipart image and optional mask. As in OpenAI's API, the mask's transparent pixels mark the area to edit. Takes the same n, size, response_format, background, output_format, and, new in v1.4.0, quality as generations; whether each reaches the provider depends on the model's route.
  • The model field takes a model ref (model:{provider}:{model}) or a virtual model (vmodel:{slug}).
  • Fields SOIT does not know are ignored rather than refused. From v1.4.0, OpenAI image parameters SOIT knows but does not send (style, moderation, output_compression, partial_images, stream, and input_fidelity on edits) are accepted at their defaults and refused with 400 at any other value. See Image options.
  • On models reached through OpenAI's Responses API (the GPT-5.5 family on an openai provider), stop is refused because that API cannot honour it, and seed is not sent.
  • Not served: the Responses API (/v1/responses), Assistants, files, audio, batch, and fine-tuning, and Anthropic's Message Batches and Files APIs.
  • On /v1/messages, top_k, metadata, service_tier, thinking, and cache_control are accepted and not sent, and disable_parallel_tool_use in tool_choice likewise; the anthropic-version and anthropic-beta headers are accepted and not interpreted. A document or other content block SOIT cannot carry, an image inside a tool_result, and tools Anthropic runs itself are refused with 400 naming them.

Response headers and ids

  • x-soit-run-id names the run the call became. A chat completion's id is chatcmpl-{run id}, and an Anthropic message's id is msg_{run id}.
  • The API lists X-SOIT-Run-Id in Access-Control-Expose-Headers, so a browser on another origin can read it.

Errors

Refusals under /v1 use OpenAI's error body without SOIT's envelope, so SDKs raise their usual exception classes:

{"error": {"message", "type", "param", "code"}}

code is SOIT's error code in lower case.

StatustypeTypical cause
400invalid_request_errorA malformed request, n above 1, an image size out of range, an image parameter SOIT does not send (v1.4.0)
401authentication_errorA missing, revoked, or expired key
402insufficient_quotaA hard-stop budget is spent (budget_exhausted), or credit is exhausted
403permission_errorThe key's scope, model list, or address list does not allow the call, or (v1.6.0) the workspace refuses calls with no price (pricing_not_configured)
404invalid_request_errorThe model is not configured in the workspace
409invalid_request_errorThe model or its provider is disabled, or the provider has no credential or governed base URL
422invalid_request_errorThe model lacks a capability the call needs, such as tools or embeddings, (v1.4.0) its route cannot carry an image option asked for, or the provider's host does not resolve

pricing_not_configured is answered before the provider is called, and a virtual model moves on to a priced target first; see Calls with no price.

Anthropic errors

New in v1.5.0. Under /v1/messages, refusals use Anthropic's body instead, so the Anthropic SDKs raise their usual exception classes:

{"type": "error", "error": {"type", "message"}}
Statustype
400invalid_request_error
401authentication_error
402billing_error
403permission_error
404not_found_error
413request_too_large
429rate_limit_error, with Retry-After
5xxapi_error

The causes are those of the table above. A request that fails validation names the fields, as Anthropic's API does (max_tokens: Field required). A failure after a stream has started arrives as an error event, since the status line is already sent. | 429 | rate_limit_error | A rate limit or quota; Retry-After says when to try again | | 5xx | api_error | The provider failed or timed out, and no virtual model target was left to try |

Streams

A streamed response starts when the model's first chunk arrives, so a refusal before the stream answers with its own status code. A failure part way through ends the stream with an OpenAI error event. A stream the client abandons fails its run with CLIENT_DISCONNECTED. From v1.4.0 every stream that reached the provider is charged, with an estimate flagged usage_estimated when the provider's usage never came.

A streamed /v1/messages call (v1.5.0) uses Anthropic's named events: message_start, ping, content_block_start, content_block_delta, content_block_stop, message_delta, and message_stop. message_start carries SOIT's estimate of the prompt's tokens, and message_delta the provider's count once it is known.

Rate limits

A call over a rate limit or a daily quota answers 429 with a Retry-After header and the code RATE_LIMIT_EXCEEDED (lower case under /v1). Per-key limits — calls per minute, calls per 24 hours, tokens per UTC day — apply on top of the key owner's own limits. From v1.4.0 the call limits count a key's tool calls through /api/v1/tools and /mcp as well as its model calls, and a refusal names the limit in details.quota (per_minute, daily_requests). A call from an address or to a model the key does not allow answers 403. See Per-key limits.

Tools

MethodPathNotes
GET/api/v1/toolsThe tools the caller may invoke: built-ins, installed plugin tools, and the tools of enabled MCP servers, each with the schema of its arguments and whether it needs approval.
GET/api/v1/tools/{ref}One tool.
POST/api/v1/tools/{ref}/invokeBody {"arguments": {...}}; optional Idempotency-Key header.

These endpoints answer in SOIT's envelope, {"success": true, "data": {...}}, not OpenAI's. data carries run_id, status (succeeded, failed, waiting_approval, or rejected), result or error, idempotency_key, and replayed. The run is also named in x-soit-run-id.

StatusMeaning
200The tool ran; a tool that ran and failed is 200 with status: failed
202The tool requires approval: status: waiting_approval with an approval_id
400The arguments do not match the tool's schema
403A tool or address the key may not use
404An unknown tool
409An Idempotency-Key reused with another tool or other arguments
  • Idempotency. The same Idempotency-Key returns the recorded outcome (replayed: true) without calling the tool again. Keys belong to the caller, so two API keys never share one. Without a key, SOIT assigns one and returns it in the Idempotency-Key response header.
  • Approval. Once a reviewer decides in Govern › Approvals, send the same call with the same key: an approved call runs and returns its result, a rejected one returns status: rejected and never runs. Only the arguments that were put up for approval can run.

MCP

MethodPathNotes
POST/mcpOne JSON-RPC message per request, answered with application/json. tools/list, tools/call, server/discover (2026-07-28), initialize and ping (earlier revisions).
GET / DELETE/mcp405: no server-to-client stream and no sessions.
GET/.well-known/oauth-protected-resource/mcpOAuth 2.1 protected resource metadata (RFC 9728) for the endpoint.
GET/.well-known/oauth-protected-resourceThe same metadata.

/mcp and /.well-known/* answer their protocols' own shapes, not SOIT's envelope. Protocol versions, headers, and error codes are covered in MCP Server.

MethodPathPurpose
POST / GET/api/v1/api-keysCreate keys (scopes, limits, allowed_tools, principal_id) and list them
PATCH/api/v1/api-keys/{key_id}Set a key's limits
GET / POST/api/v1/service-principalsList and create service principals
GET / POST/api/v1/modelhub/virtual-modelsList and create virtual models
GET / POST/api/v1/billing/budgetsList and create budgets
GET/api/v1/runs?source=gatewayRuns that came through the gateway; also filterable by api_key_id
GET/api/v1/runs/costs/entries, /api/v1/runs/costs/reconciliationCost entries and their reconciliation, filterable by key, principal, source, and the provider's upstream_id and upstream_request_id (v1.6.0)
PATCH/api/v1/workspaces/{workspace_id}unpriced_call_policy: what calls with no price do (v1.6.0)

See Identity API, ModelHub API, Runs, Tasks, and Observe API, and Budgets and Cost for the full families.

On this page