Documentation
Start using Soloniq.
Soloniq is one OpenAI-compatible API for open-weight models, served from servers in the EU. Prompts and replies are never stored. If your code already talks to the OpenAI API, you change the base URL, the key and the model name — nothing else.
Quickstart
- Get a key. Sign in at app.soloniq.com, open Keys and
create a key. It starts with
sq_live_and is shown once — store it as a server secret. - Add credit under Credits & invoices — by PayPal (plus a 2.5% fee) or bank transfer, from €30. Soloniq is prepaid in euros; you get an invoice for every payment.
- Send a request:
curl https://api.soloniq.com/v1/chat/completions \
-H "Authorization: Bearer $SOLONIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "soloniq/agent",
"max_tokens": 2000,
"messages": [{"role": "user", "content": "Hello!"}]
}'
| Base URL | https://api.soloniq.com/v1 |
|---|---|
| Authentication | Authorization: Bearer sq_live_… |
| Endpoints | POST /v1/chat/completions, GET /v1/models |
SDKs and tools
Any OpenAI-compatible client works. Set the base URL and key; use a Soloniq model name.
Python
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.soloniq.com/v1", api_key=os.environ["SOLONIQ_API_KEY"])
reply = client.chat.completions.create(
model="soloniq/agent",
max_tokens=2000,
messages=[{"role": "user", "content": "Summarise GDPR in one sentence."}],
)
print(reply.choices[0].message.content)
JavaScript / TypeScript
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://api.soloniq.com/v1", apiKey: process.env.SOLONIQ_API_KEY });
const reply = await client.chat.completions.create({
model: "soloniq/agent",
max_tokens: 2000,
messages: [{ role: "user", content: "Summarise GDPR in one sentence." }],
});
console.log(reply.choices[0].message.content);
Agent frameworks and other tools
Most tools read the standard environment variables:
OPENAI_BASE_URL=https://api.soloniq.com/v1
OPENAI_API_KEY=sq_live_…
MODEL=soloniq/agent # main model
AUX_MODEL=soloniq/agent-fast # summaries, compression, routine steps
In LiteLLM, add Soloniq as an OpenAI-compatible provider:
model_list:
- model_name: agent
litellm_params:
model: openai/soloniq/agent
api_base: https://api.soloniq.com/v1
api_key: os.environ/SOLONIQ_API_KEY
Soloniq Code: coding in the terminal
Soloniq Code sets up OpenCode, an open-source coding agent for the terminal (MIT licence), to use Soloniq models. It reads your project, edits files and runs commands like other AI coding assistants. Your code is processed only on servers in the EU and never stored.
Install
curl -fsSL https://soloniq.com/code.sh | sh
Linux and macOS; on Windows, run it inside WSL. The script installs OpenCode if needed, asks for your Soloniq key, checks it, and writes a configuration with the models your key may use. You can read the script first: soloniq.com/code.sh.
Use
cd my-project
soloniq # start
soloniq run "Add tests for utils.py" # one task, no interface
soloniq --key # use another key
soloniq --uninstall # remove Soloniq Code (OpenCode stays)
- Models. The default is
soloniq/agent. Switch with/models, for example tokimi-k2.7-codeoragent-profor harder work. - One key per developer, each with its own monthly budget. Usage in the console shows the cost per key.
- Private by default. Soloniq is the only provider; session sharing, update checks and model-list downloads
are off. Your key is stored in
~/.config/soloniq/api-key, readable only by you. - Theme. Tokyonight in terminals with full colour support; elsewhere your terminal's own colours, so the text
stays readable. To force Tokyonight:
SOLONIQ_THEME=tokyonight soloniq. - Tested versions. We pin the OpenCode version tested with Soloniq (today 1.19.5). Don't use
/updateto move to OpenCode 2; run the install command again to get the newest tested version.
Other coding tools
Coding tools that let you add an OpenAI-compatible provider work with the base URL
https://api.soloniq.com/v1, your key and a model name. Turn off the tool's own telemetry and sharing
features, so your code goes only to Soloniq.
Models and prices
Ten models from DeepSeek, Z.ai (GLM), Moonshot AI (Kimi), Alibaba (Qwen) and MiniMax — prices, context
length, image support and fallbacks for each are on the Models & pricing page.
GET /v1/models lists the models your key may use. For agents, start with these names:
| Model | What it is | Input | Cached input | Output |
|---|---|---|---|---|
soloniq/agent | Recommended default for agents — reasoning and tool calls | 0.20 | 0.05 | 0.50 |
soloniq/agent-fast | Same model with light reasoning — summaries, routine steps | 0.20 | 0.05 | 0.50 |
soloniq/agent-pro | The stronger tier — harder tasks, long agent runs (today GLM-5.3) | 1.75 | 0.44 | 4.50 |
EUR per million tokens, excluding VAT.
Aliases and fallback. agent, agent-fast and agent-pro are names, not models: they point at
the best model for the job today, so you never have to change your configuration when we upgrade. If the
default model fails or is slow, the request is answered by the backup model automatically. You pay the price
of the model that actually answered — the model field of every reply tells you which one.
Every other model has its own fallback too, listed on the price page.
You can write model names with or without the prefix: agent and soloniq/agent are the same.
Streaming
Set "stream": true to receive server-sent events in the standard OpenAI format. To get token
counts at the end of the stream, add "stream_options": {"include_usage": true}.
Tool calling
Standard OpenAI tools and tool_choice. Tool calls come back in
choices[0].message.tool_calls; send results back as role: "tool" messages.
"tools": [{
"type": "function",
"function": {
"name": "book_table",
"parameters": {"type": "object",
"properties": {"date": {"type": "string"}, "people": {"type": "integer"}},
"required": ["date", "people"]}
}
}]
Images
Send images as image_url content parts (a URL or a data:image/png;base64,… URI).
Requests with an image go to a model in the chain that can see it, billed at its price; the price page shows
which models take images. If no model in the chain can, you get 400 vision_not_supported.
Reasoning
soloniq/agent thinks before it answers. The thinking text is returned in
message.reasoning_content (don't show it to end users) and counted as output tokens
(usage.completion_tokens_details.reasoning_tokens).
- Allow enough room:
max_tokensof 2,000 or more, or the model may spend the whole budget thinking. - For quick, cheap steps use
soloniq/agent-fast, or pass"reasoning_effort": "low".
Prompt caching
Caching is automatic. When a request starts with the same text as a recent one — a fixed system prompt,
the same tool list, the conversation so far — those tokens are billed at the much lower cached-input price.
Agents resend their context constantly, so keep the beginning of your prompts stable.
Cached tokens are reported in usage.prompt_tokens_details.cached_tokens — you pay the cached price
only for tokens reported there. Cache hits are likely but not guaranteed for every request.
Keys and budgets
- One key per person, team, agent or instance. Each key has a name, your own ID or reference (an employee, a cost centre, a customer, a server), the models it may use, a monthly limit in euros and optionally a daily limit, requests per minute and tokens per minute. When a limit is reached only that key pauses. Set it all in the console under Keys (New key, Edit), or — for partners — through the Partner API.
- See who spends what: Usage shows tokens and cost per key and day, filterable by key, with CSV export.
- Keys stay on servers. Never put a key in browser or mobile code. Keys are stored hashed by us and shown to you once.
- Rotate a key in the console at any time: you get a new key, and the old one keeps working for 10 minutes.
- Block a key instantly if it leaks. A leaked key can only spend its own budget.
- Teams: invite colleagues to your account. Owners and admins see the balance, all keys and all usage; members see only the keys assigned to them and their own usage.
Limits
Every key has a requests-per-minute limit. New accounts also have a daily spending cap and a maximum number of keys; we raise them as your account builds history. You can see your current limits under Credits & invoices — or ask us for more at info@zana.ai.
Errors
Errors use the OpenAI shape: {"error": {"message", "type", "code"}}.
| Status | Code | Meaning — what to do |
|---|---|---|
| 400 | invalid_request | Check the parameters and message format. |
| 400 | context_length_exceeded | The input is longer than the model's context window. |
| 401 | invalid_api_key | Missing, wrong or revoked key. |
| 402 | budget_exceeded | The key used its monthly budget. Raise it in the console. Don't retry. |
| 402 | daily_budget_exceeded | The key used its daily budget (type budget_exceeded). It resets at midnight UTC. Don't retry. |
| 402 | balance_empty | Your prepaid balance is used up. Add credit. Don't retry. |
| 403 | key_blocked / model_not_allowed | The key is blocked, or may not use this model. |
| 404 | model_not_found | Unknown model name — see Models. |
| 429 | rate_limited / token_rate_limited / daily_limit | Too many requests or tokens this minute (type rate_limited), or the account's daily cap. Retry after a short wait; the daily cap resets at midnight UTC. |
| 503 | model_unavailable | Default and backup were both unavailable. Retry with backoff. |
Every reply carries an x-request-id header — include it when you contact us.
Privacy
- Requests are processed only on servers in the EU — our gateway and the models alike.
- Prompts, files and replies are never stored or logged, by us or by the companies that run the models. We keep counts only: time, key, model, tokens, status.
- Your data is never used for training.
- Business customers get our data processing agreement — see DPA & subprocessors.
Partner API
For partners who resell Soloniq inside their own product: create one key per customer, set its budget,
and read usage — your customers never need a Soloniq account. Create a partner key
(sq_partner_…) in the console under Invoices & webhooks; partner accounts are set up by us —
get in touch.
Base URL https://api.soloniq.com/partner/v1, header Authorization: Bearer sq_partner_…, amounts in EUR.
| Call | Body / query | Returns |
|---|---|---|
POST /keys | name, customer_ref, models, monthly_budget_eur; optional daily_budget_eur, rate_limit_rpm, rate_limit_tpm | the key (key, shown once) and its id |
GET /keys | optional customer_ref | your customer keys with spend this month (filtered by your reference) |
GET /keys/{id} | — | budgets, spent this month and today, remaining, limits, status, last use |
PATCH /keys/{id} | any of name, customer_ref, models, monthly_budget_eur, daily_budget_eur, rate_limit_rpm, rate_limit_tpm, blocked + reason; null removes a daily budget or token limit | the updated key |
POST /keys/{id}/credit | amount_eur | raises this month's budget |
POST /keys/{id}/rotate | — | a new key; the old one works 10 more minutes |
DELETE /keys/{id} | — | the key stops working |
GET /summary | — | number of keys, total spend this month |
GET /usage | from, to (YYYY-MM-DD), optional key_id | per key, per day, per model: requests, input, cached, output tokens, errors, fallbacks, cost |
curl -X POST https://api.soloniq.com/partner/v1/keys \
-H "Authorization: Bearer $SOLONIQ_PARTNER_KEY" -H "Content-Type: application/json" \
-d '{"name": "Customer 1042", "customer_ref": "cust-1042",
"models": ["agent", "agent-fast"], "monthly_budget_eur": 25, "rate_limit_rpm": 60}'
Monthly budgets run per calendar month, daily budgets per calendar day (both UTC). rate_limit_tpm
counts input + output tokens per minute — the limit that fits agents, whose cost depends on context size more
than on the number of requests. Partners are invoiced monthly for all their customers' usage.
Webhooks
Set a webhook address in the console. Events: usage.daily (yesterday's usage per key, after
02:00 UTC), key.b80 and key.b100 (budget at 80% / used up), key.blocked.
Each call is a JSON POST — {"id", "event", "created_at", "data"} — signed with your webhook secret.
Answer with any 2xx status within 10 seconds; otherwise we retry up to three times with the same id,
so ignore an id you have already processed. When one request takes a key past both thresholds,
you receive key.b80 and key.b100.
X-Soloniq-Event: key.b80
X-Soloniq-Timestamp: 1792057830
X-Soloniq-Signature: sha256=<hex HMAC-SHA256 of "timestamp.body" with your secret>
// Node.js — verify a webhook
import { createHmac, timingSafeEqual } from "node:crypto";
const expected = "sha256=" + createHmac("sha256", process.env.SOLONIQ_WEBHOOK_SECRET)
.update(`${req.headers["x-soloniq-timestamp"]}.${rawBody}`).digest("hex");
const ok = timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-soloniq-signature"]));
Reject calls whose timestamp is more than five minutes old.
Questions? info@zana.ai