Language models over an API, paid in rubles
Create a key, top up your balance and send requests to a single endpoint in the Chat Completions format. You switch between models from different developers with the model field, and the cost of each request is shown in the response and in the history.
The dashboard is at llm.liho.dev. You also sign in there to use Liho Cowork.

Three steps to the first response
Account and balance
Sign up at llm.liho.dev and top up your ruble balance in the “Balance & payments” section.
Key
Create an API key. The secret is shown only once, so save it in an environment variable.
Request
Send a POST to /v1/chat/completions. With the OpenAI SDK, change base_url and the key.
curl https://llm.liho.dev/v1/chat/completions \
-H "Authorization: Bearer $LIHO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-6-sol",
"max_tokens": 512,
"messages": [
{"role": "user", "content": "Explain what an API gateway is in two sentences."}
]
}'import os
from openai import OpenAI
client = OpenAI(
base_url="https://llm.liho.dev/v1",
api_key=os.environ["LIHO_API_KEY"],
timeout=900,
)
response = client.chat.completions.create(
model="gpt-6-sol",
max_tokens=512,
messages=[{"role": "user", "content": "Explain what an API gateway is in two sentences."}],
)
print(response.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://llm.liho.dev/v1",
apiKey: process.env.LIHO_API_KEY,
timeout: 900_000,
});
const response = await client.chat.completions.create({
model: "gpt-6-sol",
max_tokens: 512,
messages: [{ role: "user", content: "Explain what an API gateway is in two sentences." }],
});
console.log(response.choices[0].message.content);The max_tokens field is required: it is used to reserve the maximum cost of the request.
Full API referenceAn upstream tuned for agents
An agent request is not a chat message. A reasoning model can stay silent for minutes, then emit tens of thousands of tokens, and one developer runs several such streams at once. Every link on the request path in Liho LLM — the proxy, the gateway to providers, the accounting — is set up for that profile rather than for a short dialogue.
- 45 s — stream idle in the gateway
- 60 s — waiting for response headers
- ≈100 s — the CDN closes a quiet connection
One request lives up to 15 minutes. After the first token a keep-alive goes out after every 15 s without data.
How it differs from a default setup
Request lifetime
UsuallyDefault proxy and gateway timeouts are 45–100 seconds. An answer after a long think is cut while the model is still generating it.
In Liho LLM15 minutes per request, streamed or JSON. Every limit on the path — nginx, the gateway, accounting, service shutdown — is derived from that number and never fires earlier.
Silence in a stream
UsuallyA connection without data looks dead: a CDN, a load balancer or the client read timeout closes it.
In Liho LLMAfter the first token the server sends an SSE comment “: keep-alive” after every 15 seconds without data, so proxies in between keep the connection open.
Stream handling
UsuallyEvery chunk is parsed as full JSON or collected in a buffer, so the stream arrives in bursts.
In Liho LLMA streaming scanner reads only the fields it needs: 1.2 µs and 4 allocations per chunk instead of 5.2 µs and 30 with a decoder. Chunks are not merged: the largest gap inside a stream, p99, is 78 ms with an upstream interval of up to 75 ms.
Many streams at once
UsuallyA stream holds an OS thread or a large buffer, the connection pool hits its cap, and the queue grows until timeouts.
In Liho LLMA stream costs about 60–70 KiB of memory and four goroutines. Above the configured capacity the service answers 503 at once instead of queueing a request until it is cut.
Accounting on failures
UsuallyThe client got a stream, but the charge was not recorded or was recorded from an estimate.
In Liho LLMThe worst case is reserved before the model is called, and the actual usage is charged after the answer. A client disconnect does not stop accounting: the answer is drained from the provider for the exact usage.
Load-stand measurements
- Long streams with a 50–110 s reasoning pause0 of 632323 of 323
- JSON answers after 50–110 s of reasoning31 of 16796 of 96
- Requests left unsettled7680
- First stream event, p99, with an upstream interval of up to 75 ms350.7 ms80.4 ms
previous build current
An A/B on one stand: the previous build with standard gateway and proxy limits, the current one tuned for agents. The upstream is deterministic, so these are comparative numbers, not capacity guarantees.
Why this matters more for an agent than for a chat
- Reasoning without output
- Reasoning models think for minutes before the first token. To a proxy with an idle timeout such a connection looks hung.
- A cut is a lost step
- The agent repeats the whole call and pays for the input context again: for agents that is tens of thousands of tokens of history, files and tool results.
- Long output
- Editing several files is 10–30 thousand output tokens, a stream that runs for minutes.
- Parallelism
- Agents run subtasks and tools at the same time: one developer has several long streams open.
Everything about spending in one place
Keys and limits
A separate key for each app or environment. A key can have a spending limit (lifetime, or reset every day, week or month), an expiration date and a requests-per-minute limit. A revoked key stops working, but its history is kept.

Request history
Each request: model, key, input and output tokens, cache, cost, speed and status. Filters by date, model and key, daily spending charts and CSV export.

Balance
The dashboard shows your balance, the amount reserved for requests still in progress, and the available amount. The financial history lists top-ups and per-request charges.

Catalog and Playground
The catalog lists models with prices per 1M tokens and context size. From a model card you can go to the Playground and send a real request: pick a key, set a system prompt and a token limit, and turn on streaming. The request is paid from the selected key.

Pay for actual usage
- Catalog prices are in rubles per 1M input and output tokens and already include the service fee.
- Before a request, the maximum cost is reserved based on the request length and max_tokens. After the response, the actual cost is charged and the rest of the reserve returns to your balance.
- The cost of a request comes back in the API response in the usage.cost field and is shown in the history.
- Reasoning tokens are billed as output tokens.
What is supported today
- Full OpenRouter compatibility: the same request, response and error format and the same account API — /v1/key, /v1/credits, /v1/generation, /v1/keys.
- POST /v1/chat/completions: regular and streaming (SSE) responses.
- Tool calling (tools) on all catalog models.
- Reasoning level (reasoning_effort) on most models; the list of parameters is on the model card.
- GET /v1/models: the catalog available to your key.
- Key, balance and per-request accounting via /v1/key, /v1/credits and /v1/generation.
- Management keys for creating and revoking keys via the API.
In the next release
Auto mode
Liho LLM will pick the model for the task in 10 ms.
Responses API, embeddings, images and audio
The new request types arrive in the same API, paid from the same ruble balance.
Not supported
- The Anthropic Messages protocol (/v1/messages).
Liho apps and your own tools
Liho Cowork
Gets models only through Liho LLM: sign-in, catalog and payment all go through this account.
Liho IDE
Signing in to Liho LLM from the IDE creates a model connection for the agent. It can be used alongside other providers.
Your code
The OpenAI SDK for Python and TypeScript: for basic text requests, changing base_url and the key is enough.
The dashboard documentation has setup instructions for Codex CLI, Cursor, Cline, Roo Code, Aider and other tools. Check each tool’s compatibility on your own task: only the documented part of the API is supported.
Liho LLM FAQ
No, only in the documented part: Chat Completions (including streaming and tools) and the model list. The Responses API, embeddings, images and audio are not supported. Unknown request fields are dropped and listed in the X-Liho-Ignored-Fields response header.
Yes, fully: the same request and response format, errors and HTTP-Referer and X-Title headers, and the same account API — /v1/key, /v1/credits, /v1/generation, /v1/keys. To switch, change base_url to https://llm.liho.dev/v1 and the key.
Input tokens are multiplied by the input price and output tokens by the output price; for models with a cached input price, cached tokens are billed at that price. Prices are in rubles per 1M tokens, per the catalog at the time of the request.
That is the reserve: before a request, the maximum cost based on max_tokens is held. After the response, the actual amount is charged and the rest of the reserve is returned right away. The dashboard shows the reserve separately from the balance.
Under the privacy policy, the service does not store the text of requests and responses, only metadata: model, tokens, cost, time. Model providers process requests under their own terms.
Yes. Create a separate key for the app and set a spending limit and a requests-per-minute limit. Once the limit is reached, the key gets a 402 response.
No. The service is prepaid: requests are paid from your balance.
Get a key and send your first request
Sign up at llm.liho.dev. A step-by-step example with curl, Python and streaming is in the guide.