Make your first call
This is the Chat Completions API. Any OpenAI-compatible client works: change the base URL and the key and keep everything else.
- Base URL
https://api.tiyuvta.ai/v1- Auth
Authorization: Bearer <your key>- Model
qwen/qwen3.8-27b
curl https://api.tiyuvta.ai/v1/chat/completions \
-H "Authorization: Bearer $TIYUVTA_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "qwen/qwen3.8-27b",
"messages": [{"role": "user", "content": "Say hello."}]
}'
No key yet? Sign in with an email address. The
first 100 accounts receive $10 of
credit, with no card required. GET https://api.tiyuvta.ai/v1/models
is the authoritative roster; the model page lists
what is live and what is in bring-up.
Stream tokens
Usage is reported in the stream, so spend can be metered without a second request.
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.tiyuvta.ai/v1",
apiKey: process.env.TIYUVTA_KEY,
});
const stream = await client.chat.completions.create({
model: "qwen/qwen3.8-27b",
messages: [{ role: "user", content: "Write a haiku about caches." }],
stream: true,
stream_options: { include_usage: true },
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
if (chunk.usage) console.error(chunk.usage);
} Call tools
Function calling is constrained during decoding, so the model cannot emit a call that violates the schema you sent.
r = client.chat.completions.create(
model="qwen/qwen3.8-27b",
messages=[{"role": "user", "content": "What is the weather in Haifa?"}],
tools=[{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"],
},
},
}],
tool_choice="auto",
)
print(r.choices[0].message.tool_calls) Force a JSON shape
response_format takes JSON mode or a JSON schema. A strict
schema is enforced token by token rather than checked afterwards.
r = client.chat.completions.create(
model="qwen/qwen3.8-27b",
messages=[{"role": "user", "content": "Extract the invoice fields."}],
response_format={
"type": "json_schema",
"json_schema": {
"name": "invoice",
"strict": True,
"schema": {
"type": "object",
"properties": {
"total": {"type": "number"},
"currency": {"type": "string"},
},
"required": ["total", "currency"],
"additionalProperties": False,
},
},
},
) Send an image
Images go in the same message as text, as image_url content
parts — a URL or a data URL. They are billed as input tokens at
$0.38 per million, the same rate as text input, and
the reply is text.
r = client.chat.completions.create(
model="qwen/qwen3.8-27b",
messages=[{
"role": "user",
"content": [
{"type": "text", "text": "What does this chart show?"},
{"type": "image_url", "image_url": {
"url": "https://example.com/chart.png",
}},
],
}],
)
print(r.choices[0].message.content)
# A data URL works too: data:image/png;base64,<...> Pay less on long chats
When a request continues a conversation the endpoint already served, the shared prefix is read from cache: cheaper and much faster to first token. Nothing to enable.
# Turn 1 — the model reads 5,700 tokens of context.
messages = [system, big_context, {"role": "user", "content": "Summarise."}]
first = client.chat.completions.create(model=MODEL, messages=messages)
# Turn 2 — same prefix, one turn longer. The shared prefix is a cache hit,
# billed at $0.12 per million instead of $0.38.
messages += [first.choices[0].message, {"role": "user", "content": "Now list risks."}]
second = client.chat.completions.create(model=MODEL, messages=messages)
print(second.usage.prompt_tokens_details.cached_tokens) Two practical consequences: append to a conversation rather than rebuilding it, and keep the system prompt stable at the front where it can be reused.
Read what you were billed
Every response carries exact counts. Input tokens are split so you can see the cached share you paid $0.12 for instead of $0.38.
"usage": {
"prompt_tokens": 5821,
"prompt_tokens_details": { "cached_tokens": 5690 },
"completion_tokens": 412,
"total_tokens": 6233
} The same figures, per day and per key, are in your console under Usage. Bodies of prompts and completions are not stored to produce them.
Errors
| Status | Meaning | What to do |
|---|---|---|
| 401 | Key missing, malformed or revoked. | Check the header, then the key list in your console. |
| 402 | Prepaid balance cannot cover the request. | Top up, then retry. Nothing was charged and nothing was generated. |
| 422 | The request body is not one we can serve — unknown model, bad schema, prompt over the window. | The message names the field. It will not be silently truncated. |
| 429 | Rate limit, or capacity shed instead of queued. | Back off and retry. Requests are refused quickly rather than held open. |
| 5xx | Our fault. | Retry with backoff. If it persists, mail hello@tiyuvta.ai with the time window. |
{
"error": {
"message": "tenant prepaid balance is insufficient for this request",
"type": "insufficient_balance",
"code": "insufficient_balance"
}
} Rate limits
- How they work
- Rate limits are per account and exist for abuse control. We scale capacity with demand, so there is no published ceiling to design around.
- Trial credit
- Runs at a lower rate than purchased credit.
- Need more
- Mail hello@tiyuvta.ai with the shape of your traffic and we raise them.
- When you hit one
-
429, refused quickly rather than queued. Back off and retry; nothing was charged.
Move from another provider
Two lines change. There is no proprietary SDK and no request translation layer.
- base_url="https://api.openai.com/v1"
- model="gpt-4o-mini"
+ base_url="https://api.tiyuvta.ai/v1"
+ model="qwen/qwen3.8-27b"
Things to check when you switch: this model thinks by default, so budget
output tokens for reasoning or lower reasoning_effort, and
the context window is 262,144 tokens
shared between input and output.
Keys and security
- A key is shown once, at creation. We store only its prefix, so we cannot email it back to you.
- Create as many as you like and revoke any of them immediately; revocation takes effect on the next request.
- Keys are account-wide. Usage is reported per key so you can tell which service spent what.
- Never put a key in a browser or a mobile app. Proxy it from your own server.
- If a key leaks, revoke it first, then contact us.