API keys

GPU service in validation

Build with Vuto.

OpenAI-compatible chat completions. GPU inference is still being validated.

Sign in to create and manage API keys in your console.

API essentials

Use your OpenAI client.

Set baseURL, your key, and the model ID.

export VUTO_BASE_URL="https://vuto.ai/v1"
export VUTO_API_KEY="paste_your_key_here"

curl "$VUTO_BASE_URL/chat/completions" \
  -H "Authorization: Bearer $VUTO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vuto-code-1",
    "reasoning_effort": "low",
    "messages": [
      {"role": "user", "content": "Say hello in one sentence."}
    ]
  }'

Authenticate every request.

Every /v1 endpoint, including GET /v1/models, requires a bearer key. Anthropic clients can send the same key in an x-api-key header instead.

Connection
Base URL https://vuto.ai/v1
Model vuto-code-1
Header Authorization: Bearer <your key>
Account Sign in at /console to view balance and usage history.
Note

Keys are shown once, at creation, and can't be re-displayed. Call this API from a server you control, not directly from browser JavaScript: the API does not send CORS headers for cross-origin requests, and a bearer key placed in client-side code is visible to anyone who opens it.

Stream a response.

Set "stream": true and the response becomes text/event-stream: a series of chat.completion.chunk objects ending with data: [DONE].

Note

A final chunk carries usage by default. Send "stream_options": {"include_usage": false} to leave it out, or {"include_usage": true} to make the request explicit. The official OpenAI SDKs send that automatically from their .stream() helper. stream_options on a request that isn't streaming returns 400 unsupported_parameter.

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://vuto.ai/v1",
  apiKey: process.env.VUTO_API_KEY
});

const stream = client.chat.completions.stream({
  model: "vuto-code-1",
  messages: [{ role: "user", content: "Say hello in one sentence." }]
});

stream.on("content.delta", ({ delta }) => process.stdout.write(delta));

const completion = await stream.finalChatCompletion();
console.log("\n" + completion.choices[0].message.content);

Use Claude Code and Anthropic SDKs.

Vuto also answers the Anthropic Messages API at POST /v1/messages. Set the client's base URL to https://vuto.ai without /v1, because Anthropic clients add the path themselves, and use your Vuto key.

Claude Code

{
  "env": {
    "ANTHROPIC_BASE_URL": "https://vuto.ai",
    "ANTHROPIC_AUTH_TOKEN": "paste_your_key_here",
    "ANTHROPIC_MODEL": "vuto-code-1",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "vuto-code-1",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "vuto-code-1",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "vuto-code-1",
    "CLAUDE_CODE_MAX_CONTEXT_TOKENS": "131072",
    "CLAUDE_CODE_MAX_OUTPUT_TOKENS": "8192"
  }
}

Put the env block in ~/.claude/settings.json, not in a project file you commit: it holds your key. ANTHROPIC_AUTH_TOKEN sends the key as a bearer token and ANTHROPIC_API_KEY sends it as x-api-key; Vuto accepts both. Claude Code asks for a model by tier for background work, so the three ANTHROPIC_DEFAULT_*_MODEL variables point every tier at vuto-code-1, and Vuto also serves any claude-* model name with vuto-code-1. The model reads 131,072 tokens of context, while Claude Code assumes 200,000 for a model it does not know: CLAUDE_CODE_MAX_CONTEXT_TOKENS makes it compact the conversation before it outgrows that window. A request that still overflows gets a prompt is too long error, which Claude Code also answers by compacting. Replies stop at 8,192 tokens, and CLAUDE_CODE_MAX_OUTPUT_TOKENS gives Claude Code the same budget.

Anthropic SDKs and OpenCode

import os
import anthropic

client = anthropic.Anthropic(
    base_url="https://vuto.ai",
    api_key=os.environ["VUTO_API_KEY"],
)

message = client.messages.create(
    model="vuto-code-1",
    max_tokens=1024,
    output_config={"effort": "low"},
    messages=[{"role": "user", "content": "Say hello in one sentence."}],
)

print(message.content[0].text)

The SDKs stream with stream=True or their messages.stream() helpers. output_config.effort sets the model's reasoning effort to low, medium or high; xhigh and max run as high. Leave it out and the model reasons at its default, which can spend a short max_tokens budget before any visible text. OpenCode reaches Vuto through chat completions: opencode.json declares Vuto as a custom provider with the OpenAI-compatible package, as the OpenCode providers guide describes.

Messages

POST /v1/messages

How /v1/messages handles request fields
Field Handling
model vuto-code-1 or one of its aliases. A claude-* name runs on vuto-code-1, and every response names vuto-code-1.
messages, system Text, tool_use and tool_result blocks, plus system turns inside the conversation. Vuto drops thinking blocks from earlier turns. Vuto does not support response prefill, so the list cannot end with an assistant message.
max_tokens Required. A value above 8192 runs as 8192.
stream Anthropic events from message_start to message_stop. Text arrives as the model writes it; each tool_use block arrives whole when the turn ends. message_start carries an estimate of input_tokens, and message_delta carries the billed usage.
tools, tool_choice Custom tools only: names up to 128 characters, descriptions up to 8,192, and no cap on the count. Claude Code sends the schema of every connected MCP tool with each request, so each one uses context. auto and any leave the call to the model, so Vuto does not enforce any; tool names one function; none removes the tools.
thinking, output_config.effort Set the reasoning effort. Vuto never returns thinking text.
temperature, top_p, stop_sequences, metadata.user_id Vuto passes them to the model, with up to 4 stop sequences, and hashes user_id the same way as user on chat completions.
cache_control, context_management, service_tier, top_k Vuto accepts and ignores them.
Server tools, mcp_servers, container, safeguards, output_config.format 400 invalid_request_error: Vuto runs no web search, web fetch, code execution, MCP connector, tool-use classifier or structured output enforcement. Claude Code then resends without safeguards and keeps its own auto mode checks.
Limits

The model reads text only. Vuto refuses an image or document in a user message with capability_rejected: image_block (or document_block), so Claude Code removes it and retries, and replaces one inside a tool_result with a short note. No message or tool count cap applies: the 512 KiB body limit and the 131,072-token context bound a request, and past either Vuto answers prompt is too long, which makes Claude Code compact the conversation. Claude Code sends one request per model turn, and each one counts toward the per-key request rate under Rate limits. /v1/messages/count_tokens is not available. After an idle period the first request can return 503 with an overloaded_error that carries the model_warming or model_offline message and a Retry-After header; Vuto does not charge the failed request.

Errors

Errors on /v1/messages use Anthropic's shape, {"type":"error","error":{"type":...,"message":...}}, and keep the HTTP status, Retry-After and x-request-id: 400 invalid_request_error, 401 authentication_error, 404 not_found_error, 413 request_too_large, 429 rate_limit_error for rate limits and insufficient balance, 503 overloaded_error, other 5xx api_error. Insufficient balance, model_warming and model_offline carry x-should-retry: false, so the SDKs return them at once instead of waiting out Retry-After.

API reference

Authenticated endpoints for models, chat, decisions and usage.

Models

GET /v1/models

Lists configured public models and their current rates. When JEV is enabled, vuto-jev-1 lists /v1/decisions as its endpoint.

Example response
{
  "object": "list",
  "data": [
    { "id": "vuto-code-1", "object": "model", "created": 0, "owned_by": "vuto" }
  ]
}

vuto-code-1 is Vuto's stable public model id. It is a transparent alias over the configured preview upstream, not a claim of proprietary weights or verified Vuto-hosted inference. vuto-grandmaster-1 is the name on the box, and vuto-lilt, vuto-lilt-01 and vuto-5.2 remain accepted legacy aliases.

Chat completions

POST /v1/chat/completions

Generates a reply as JSON, or as an SSE stream when stream is true. Request bodies over 524,288 bytes (512 KiB) are rejected with 413 request_too_large.

Parameters
Name Type Notes
model Required string Must be vuto-code-1, the id returned by GET /v1/models.
messages Required array

1 to 64 messages; combined message content up to 200,000 characters.

Each message: role (system, user, assistant, or tool), content (string, or null for an assistant message carrying tool_calls), optional name (≤64 characters), and tool_call_id (required, ≤128 characters, only on tool messages).

stream Optional boolean Default false.
stream_options Optional object { include_usage: boolean }. Only valid when stream is true. See Streaming.
max_tokens / max_completion_tokens Optional integer Aliases for the same value; if both are sent they must match. 1 to 8192, default 1024.
temperature Optional number 0 to 2.
reasoning_effort Optional string low, medium, high, or max. Supported by vuto-code-1 for JSON and streaming; medium maps to high. Omission keeps the model default, currently max. Use low for short output budgets: reasoning at max can leave no visible text. Other values, including null, return 400 invalid_parameter; models without this capability return 400 unsupported_parameter. Also accepted by the MCP vuto_chat tool.
top_p Optional number 0 to 1.
stop Optional string or array A string, or 1 to 4 strings, each ≤1024 characters.
tools Optional array 1 to 128 function definitions, when the selected model supports tools. Each definition has type: "function" and a function object with name, optional description (up to 8,192 characters), parameters (a JSON schema object), and strict (boolean).
tool_choice Optional string or object Requires tools. Use none, auto, required, or {"type":"function","function":{"name":"your_function"}} naming one of the supplied tools.
user Optional string ≤512 characters. Hashed into an opaque per-caller identifier server-side; Vuto does not store or forward the raw value.
Model capabilities

Function calling depends on the selected model's provider capabilities. Models without tool support reject tools and tool_choice with 400 unsupported_parameter. Any request key outside the table above, including n, response_format, seed, logprobs, presence_penalty, and frequency_penalty, returns 400 unsupported_parameter.

Example response (stream: false)
{
  "id": "chatcmpl_9f4c2a5e6b7a4c1e9e2a5f3b7c8d1a90",
  "object": "chat.completion",
  "created": 1754297400,
  "model": "vuto-code-1",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Hello! How can I help today?" },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 12,
    "completion_tokens": 9,
    "total_tokens": 21,
    "prompt_tokens_details": { "cached_tokens": 0 }
  }
}

finish_reason is one of stop, length, tool_calls, or content_filter.

Typed decisions (JEV)

POST /v1/decisions

Use the same bearer key and prepaid balance as chat. Send text or JSON state and 1 to 32 named questions. Each question has text instructions and a type: noul returns the probability of yes; choice takes 2 to 255 named options in a criteria object; score takes 2 to 10 ordered text levels in a criteria array. Choice descriptions may be text or null. Noul criteria may describe true and false.

{"model":"vuto-jev-1","state":"The export button fails.","questions":{"urgent":{"type":"noul","instructions":"Is this urgent?"}}}

The response contains answers under your question IDs and usage.input_tokens / usage.output_tokens. Choice and score include probabilities and confidence; a score uses zero-based levels. These are judgments, not guarantees. JEV accepts no image/audio inputs or streaming. Unknown request fields are rejected; the body limit is 512 KiB and the provider context limit is 64k tokens per question.

JEV uses the default model's current rate card, with zero cached tokens. A temporary credit hold covers up to 64k input and 64k output tokens per question; only reported usage is charged, and the remainder is released. Calls fail with 503 feature_unavailable until Vuto configures its dedicated provider key. Upstream credit exhaustion returns 503 provider_quota_exhausted.

Public GET /__vuto/features returns {"jev_enabled":false} or {"jev_enabled":true}. Show a JEV badge only when true. This reports configuration, not a live provider health check.

Usage

GET /v1/usage

Reads current prepaid balance and recorded usage for one UTC day. Omit day for today, or request /v1/usage?day=2026-09-10 for a past date. Invalid, future or repeated dates return 400 invalid_usage_day. The balance remains current.

Agents can call vuto_usage on /mcp with the same bearer key. Pass {"day":"2026-09-10"} as tool arguments, or {} for today. It returns recorded usage as JSON text and structuredContent, without running inference or spending credits. Request limits still apply.

Totals cover all models on your account. When a model registry is available, default_model identifies the model priced by rate_card, and rate_cards lists each public model with its current rates in integer microcredits per million tokens. These rates apply to new requests; recorded charges keep their original prices.

Example response
{
  "object": "usage.summary",
  "day": "2026-08-04",
  "unit": "microcredit",
  "balance_microcredits": 1487500,
  "rate_card": {
    "id": "vuto-code-beta-q4-20260909",
    "applies_to": "new_requests",
    "input_microcredits_per_million_tokens": 1000000,
    "cached_input_microcredits_per_million_tokens": 200000,
    "output_microcredits_per_million_tokens": 3000000
  },
  "inputTokens": 812,
  "cachedInputTokens": 0,
  "outputTokens": 231,
  "costMicrocredits": 1735,
  "requests": 4,
  "recent": [
    {
      "requestId": "req_2f6a...",
      "model": "vuto-code-1",
      "status": "settled",
      "costMicrocredits": 612,
      "latencyMs": 940,
      "createdAt": "2026-08-04T10:02:11.000Z"
    }
  ]
}
Note

The per-day totals (inputTokens, cachedInputTokens, outputTokens, costMicrocredits, requests, recent) use their internal camelCase names rather than the snake_case used elsewhere in this response, reproduced above exactly as the API returns them. recent holds up to the 20 most recent settled requests for the day, newest first.

Errors

Every error outside /v1/messages uses the same envelope; /v1/messages answers in Anthropic's error shape. Every response also carries an x-request-id header.

Error envelope
{
  "error": {
    "message": "Invalid parameter.",
    "type": "invalid_request_error",
    "code": "invalid_parameter",
    "param": "temperature"
  }
}

type is one of authentication_error, invalid_request_error, rate_limit_error, insufficient_quota, provider_error, model_warming, model_offline, or internal_error.

Codes
Status Code When
400invalid_parameterA field failed validation. See param.
400unsupported_parameterAn unknown or currently-unavailable field was sent. See param.
400invalid_jsonThe request body is not valid JSON.
400context_length_exceededThe prompt and max_tokens exceed the model's context. The message starts with prompt is too long, usually followed by N tokens > M maximum. Shorten the conversation; the same request fails again.
401invalid_api_keyThe bearer key is missing, malformed, or revoked.
403https_requiredThe request used plain HTTP. Use https://vuto.ai/v1 and revoke any key sent without HTTPS.
404model_not_foundmodel is not vuto-code-1 or one of its aliases.
404not_foundThe path is not a documented /v1 endpoint.
405method_not_allowedWrong HTTP method for a valid path.
413request_too_largeRequest body over 512 KiB.
429rate_limit_exceededPer-key or platform request rate exceeded. Retry-After header is set.
429insufficient_quotaAccount balance can't cover the request's worst-case cost.
429provider_rate_limitedThe upstream model is temporarily rate limited. Retry.
499request_abortedThe client disconnected before the response completed.
502provider_error / invalid_provider_response / invalid_provider_usage / provider_response_too_largeThe upstream model returned something Vuto couldn't validate. Retry.
503model_warmingThe model is starting or may be starting. Read Retry-After. The failed request is not charged.
503model_offlineNo GPU is running. Retry after 30 minutes. The failed request is not charged.
504provider_timeoutThe upstream model did not respond within 300 seconds.
500internal_error / accounting_errorAn unexpected server-side failure.
Note

If a stream disconnects mid-response after the 200 status has already been sent, Vuto ends it with an inline error chunk followed by data: [DONE] rather than closing silently.

Rate limits & free keys

Current limits for the beta. All of these can change as the beta progresses.

60 / min

Per-key request rate

Requests beyond this return 429 rate_limit_exceeded with a Retry-After header.

600 / min

Platform-wide request rate

Shared across every key while the beta is capacity-limited.

Not available

Free key balance

Free keys are not currently being issued.

5 / day

Free keys per IP address

Beyond this, or beyond 100 issued platform-wide per day, requests return 429 with a Retry-After header.

Chat completion requests time out with 504 provider_timeout after 300 seconds without an upstream response.

Access & billing

Key availability follows the current beta configuration. Paid credit packs are listed below.

Keys
Created once and shown once
Balance
Available from /v1/usage
Billing
Prepaid credit packs
Prompts
Vuto keeps the text of the latest message in each API request for up to 30 days so the team can review usage and prevent abuse.
5.00 USD

5 credits

Pack credits-5. Settled in USDC on Base, charged once.

25.00 USD

27 credits

Pack credits-25. Settled in USDC on Base, charged once.

100.00 USD

115 credits

Pack credits-100. Settled in USDC on Base, charged once.

Credits are prepaid, non-transferable, and do not expire on their own. Card checkout is unavailable. Check model availability in your console before buying.

View payment options in your console.