Orquesta Batuta LLM API
OpenAI-compatible chat completions proxy with smart per-prompt model routing.
OpenAI-compatible chat completions proxy with smart per-prompt model routing.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/getorquesta-com:getorquesta-com-batuta-llm-api"
curl "https://apis.io/api/v1/apis?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Orquesta Public Batuta LLM API
version: '1.0'
summary: Programmatic access to prompts, logs, projects, agents, users, and the Batuta LLM proxy.
description: 'The Orquesta Public API exposes read access to your organization''s prompts, execution logs,
projects, agents, and users, plus an OpenAI-compatible chat-completions proxy ("Batuta LLM")
that routes across multiple upstream models with smart per-prompt classification.
All endpoints under `/api/v1/*` are stable, versioned, and safe to integrate against. Internal
dashboard endpoints (`/api/projects/[id]/batuta/*`, `/api/agent/*`, `/api/auth/*`, etc.) are
NOT part of this contract and may change without notice.
## Authentication
Pass an API key on every request via either header:
- `Authorization: Bearer `
- `X-API-Key: `
Three token prefixes are accepted; each carries different scope semantics:
| Prefix | Type | Scope | Scopes granted |
|----------|-------------------|-------------------|---------------------------------------------------------|
| `oak_` | Org API key | Organization, or a chosen subset of its projects | DB-configured (any of `prompts:read`, `prompts:write`, `logs:read`, ...) |
| `oclt_` | CLI token | Organization | All four read scopes (synthesized), plus prompt submit |
| `oat_` | Agent token | Project (single) | All four read scopes; queries restricted to its project |
An `oclt_` inherits its creator''s access: an org owner or admin reaches every project,
anyone else only the projects they are a member of. Projects outside that set are
reported as not found.
An `oak_` is org-wide unless it was restricted to specific projects when it was created
(or edited afterwards). A restricted key sees only those projects in every listing, and
a request naming any other project is reported as not found — the same answer as a
project that does not exist, so a key cannot enumerate the organization.
Generate keys from the dashboard: https://getorquesta.com/dashboard/settings
## Errors
Non-Batuta endpoints return `{ "error": "human-readable message" }` with status codes
401 (missing/invalid key), 403 (scope/project mismatch), 404 (not found), 500 (internal).
Batuta proxy endpoints (`/chat/completions`, `/models`) return OpenAI-compatible errors:
`{ "error": { "message": "...", "type": "auth_error" | "billing_error" | "routing_error" | "proxy_error" } }`.'
contact:
name: Orquesta Support
url: https://getorquesta.com
email: oscar@getorquesta.com
license:
name: Proprietary
servers:
- url: https://getorquesta.com
description: Production
security:
- BearerAuth: []
- ApiKeyAuth: []
tags:
- name: Batuta LLM
description: OpenAI-compatible chat completions proxy with smart per-prompt model routing.
paths:
/api/v1/chat/completions:
post:
tags:
- Batuta LLM
summary: Create a chat completion (OpenAI-compatible)
description: 'OpenAI-compatible chat completions endpoint. Pass any model id from `GET /models` as the
`model` field; pass the synthetic id `batuta-auto` to let Batuta classify the prompt and
route to a tier (fast / balanced / premium) automatically.
### Routing headers (optional)
- `X-Batuta-Force-Tier: fast | balanced | premium` — bypass the classifier and pin a tier
for this call. Only meaningful when `model = batuta-auto`.
- `X-Batuta-Session-ID: ` — opaque session id. When provided, the proxy attributes
prior assistant turns in this session to the model that produced them so downstream
models can calibrate trust on cross-model conversations.
### Routing response headers
- `X-Batuta-Routed-From: batuta-auto` (when input was routed)
- `X-Batuta-Routed-To: `
- `X-Batuta-Tier: fast | balanced | premium`'
operationId: createChatCompletion
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ChatCompletionRequest'
examples:
simple:
summary: Plain GPT-4o call
value:
model: gpt-4o-mini
messages:
- role: user
content: What is the capital of France?
batuta-auto:
summary: Let Batuta classify and route
value:
model: batuta-auto
messages:
- role: user
content: Refactor this large codebase to use async/await.
forced-tier:
summary: Force premium tier (use with X-Batuta-Force-Tier header)
value:
model: batuta-auto
messages:
- role: user
content: Plan a multi-service migration.
parameters:
- in: header
name: X-Batuta-Force-Tier
required: false
schema:
type: string
enum:
- fast
- balanced
- premium
description: Pin the routing tier. Only honored when `model = batuta-auto`.
- in: header
name: X-Batuta-Session-ID
required: false
schema:
type: string
format: uuid
description: Opaque per-conversation id for cross-model attribution.
responses:
'200':
description: Successful completion (or first SSE chunk if `stream=true`).
headers:
X-Batuta-Routed-From:
schema:
type: string
description: Original requested model. Present only when routing happened.
X-Batuta-Routed-To:
schema:
type: string
description: Actual upstream model that produced the completion.
X-Batuta-Tier:
schema:
type: string
enum:
- fast
- balanced
- premium
description: Tier chosen (or forced) for this call.
content:
application/json:
schema:
$ref: '#/components/schemas/ChatCompletionResponse'
text/event-stream:
schema:
type: string
description: 'SSE stream of `data: {json}\n\n` chunks when `stream=true`.'
'400':
$ref: '#/components/responses/BatutaInvalidRequest'
'401':
$ref: '#/components/responses/BatutaAuthError'
'429':
description: Token quota exceeded for this billing tier.
content:
application/json:
schema:
type: object
properties:
error:
type: object
properties:
message:
type: string
type:
type: string
enum:
- billing_error
usage:
type: object
properties:
tokens_used:
type: integer
token_limit:
type: integer
tokens_remaining:
type: integer
'500':
$ref: '#/components/responses/BatutaProxyError'
/api/v1/models:
get:
tags:
- Batuta LLM
summary: List models available through the Batuta proxy (OpenAI-compatible)
operationId: listModels
responses:
'200':
description: Model catalog.
content:
application/json:
schema:
type: object
properties:
object:
type: string
enum:
- list
data:
type: array
items:
$ref: '#/components/schemas/ModelInfo'
'401':
$ref: '#/components/responses/BatutaAuthError'
'403':
$ref: '#/components/responses/BatutaBillingError'
components:
responses:
BatutaInvalidRequest:
description: Malformed request body (missing model, messages, etc.).
content:
application/json:
schema:
$ref: '#/components/schemas/BatutaErrorEnvelope'
BatutaProxyError:
description: Internal proxy error or upstream failure.
content:
application/json:
schema:
$ref: '#/components/schemas/BatutaErrorEnvelope'
BatutaBillingError:
description: Batuta LLM access denied (no subscription, suspended, etc.).
content:
application/json:
schema:
$ref: '#/components/schemas/BatutaErrorEnvelope'
BatutaAuthError:
description: Missing or invalid Batuta proxy token.
content:
application/json:
schema:
$ref: '#/components/schemas/BatutaErrorEnvelope'
schemas:
BatutaErrorEnvelope:
type: object
required:
- error
properties:
error:
type: object
required:
- message
- type
properties:
message:
type: string
type:
type: string
enum:
- auth_error
- billing_error
- invalid_request
- routing_error
- proxy_error
- server_error
ModelInfo:
type: object
required:
- id
- object
- owned_by
properties:
id:
type: string
object:
type: string
enum:
- model
created:
type: integer
owned_by:
type: string
name:
type: string
max_tokens:
type: integer
ChatCompletionRequest:
type: object
required:
- model
- messages
properties:
model:
type: string
description: 'Any id returned by `GET /models`, or the synthetic `batuta-auto` to enable
classifier-driven routing.
'
examples:
- batuta-auto
- gpt-4o-mini
- claude-sonnet-4-6
- claude-opus-4-7
messages:
type: array
minItems: 1
items:
$ref: '#/components/schemas/ChatMessage'
stream:
type: boolean
default: false
temperature:
type: number
minimum: 0
maximum: 2
max_tokens:
type: integer
minimum: 1
tools:
type: array
items:
type: object
properties:
type:
type: string
enum:
- function
function:
type: object
properties:
name:
type: string
description:
type: string
parameters:
type: object
description: JSON Schema for the function arguments
tool_choice:
oneOf:
- type: string
enum:
- auto
- none
- required
- type: object
properties:
type:
type: string
enum:
- function
function:
type: object
properties:
name:
type: string
ChatCompletionResponse:
type: object
required:
- id
- object
- created
- model
- choices
properties:
id:
type: string
object:
type: string
enum:
- chat.completion
created:
type: integer
description: Unix epoch seconds
model:
type: string
description: The upstream model that actually generated the completion
choices:
type: array
items:
type: object
properties:
index:
type: integer
message:
$ref: '#/components/schemas/ChatMessage'
finish_reason:
type: string
nullable: true
enum:
- stop
- length
- tool_calls
- content_filter
- null
usage:
type: object
properties:
prompt_tokens:
type: integer
completion_tokens:
type: integer
total_tokens:
type: integer
ChatMessage:
type: object
required:
- role
- content
properties:
role:
type: string
enum:
- system
- user
- assistant
- tool
content:
type: string
name:
type: string
tool_calls:
type: array
items:
type: object
properties:
id:
type: string
type:
type: string
enum:
- function
function:
type: object
properties:
name:
type: string
arguments:
type: string
description: JSON-encoded arguments
tool_call_id:
type: string
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: orquesta-token (oak_|oclt_|oat_)
ApiKeyAuth:
type: apiKey
in: header
name: X-API-Key
x-provenance:
method: harvested
publisher: Orquesta
source: https://getorquesta.com/openapi.json
note: split by refine-openapis from the provider's own published document, verified by fetch (openapi/_original/*.fetch.json);
stamped by stamp-openapi-provenance.py (roadmap#793)