POST /v1/proxy/anthropic/v1/messages and POST /v1/proxy/openai/v1/chat/completions are compatibility endpoints: their whole point is that a client you already have works unchanged. These are the typed way to reach them from this client, for the case where you want one model call — any catalogue id, vetta/auto included — and none of the machinery a session brings: no agent, no tools run for you, no event log, no state between calls. Both bill the organization directly, and the ledger entry carries no session or agent id.
If you want a durable agent that keeps working across turns, use sessions.create instead.
messages
POST /v1/proxy/anthropic/v1/messages.
string
required
A Vetta model id, exactly as
models.list returns it.ModelSelectionPolicy
Optional.
{ options: { "<model id>": "<what it is for>", … }, min_confidence? } — let the router pick which of these ids answers this call, model being the default. The reply’s model names the pick; the selector’s input tokens are one more input line on the same ledger entry. See model auto-selection.object[]
required
The conversation. Each turn is
{ role: "user" | "assistant", content }, and content is a string or an array of text / tool_use / tool_result blocks.integer
required
The output allowance. It sets the size of the pre-flight quote held against your balance.
string
The system prompt.
object[]
Tools the model may call, each
{ name, description?, input_schema }. You run them and send the results back as tool_result blocks.window is the second argument, not a body field: the Messages format has no room for a completion window, so it travels as the Vetta-Window header. Unset means immediate, and a window is never quietly downgraded — a model with no published price in the window you asked for is refused with window_unavailable before anything is spent.
id (the request id, the same value as the x-request-id header and the ledger entry), content, stop_reason, and usage with the format’s four token counters. The exact five-tier split you were charged on is on credits.ledger.
There is deliberately no streaming method. Set up a Messages-format client against <baseUrl>/v1/proxy/anthropic and stream with that — keeping it working unchanged is what the endpoint is for. Fields the endpoint cannot carry (temperature, top_p, stop_sequences, thinking, …) are absent from ProxyMessageCreate for the same reason the server refuses them: a silently dropped setting is a call you paid for and did not ask for.
Configuring an agent’s tools
Not a route, and not onclient.proxy — but it belongs next to it, because both are things you write rather than read. An agent’s toolset is a field on the agent, and configs is replaced wholesale on the wire, so changing one tool by hand means resending every other one unchanged. withTool does that for you:
config merges key by key, so setting a cap does not clear a domain filter. A tool named for the first time is created enabled at the toolset’s own default permission. WebToolConfig types the domain filters and content cap that web_search and web_fetch read; MediaToolConfig types the models default that generate_image and generate_video read — the first id is what runs when the agent names none, and it is a default, not an allow-list (see generation tools).
completions
POST /v1/proxy/openai/v1/chat/completions. The same proxy in the Chat Completions dialect, for a client that speaks that envelope and nothing else.
Same balance, same rate card, same meter as messages — only the envelope differs; model_selection works the same way here. max_completion_tokens (or max_tokens) is optional here, unlike the Messages door: omit it and the call is bounded by whatever the model may emit.
Like its sibling, there is no streaming method: a client that streams this dialect already has one, and the endpoint exists so that client keeps working. Point it at <baseUrl>/v1/proxy/openai.
calls
GET /v1/proxy/calls. Every proxied call leaves a trace beside its ledger entry: the key that sent it, the model that actually answered, what the vendor charged us, and the literal prompt and reply. Newest first, keyset-paged like every other list; every row carries its bodies inline.
Needs a key with audit:read, not the proxy:write that makes the calls. The scope you hand to a sandbox or a third-party client cannot read back what your organization has been sending; see Call traces for what is stored and who can read it.
call
GET /v1/proxy/calls/{request_id}. One trace, addressed by the request id you already have: it is the id on the reply, the value on x-request-id, and the idempotency key of the call’s ledger entry — one call, one identifier, three places.
This read returns the literal request and response. Only a row written before the current capture can say metadata or object, with null bodies; expires_at is null on every new row.