Text models use the chat completions format that most chat clients already speak. If you have code that calls a chat model today, you change the base URL to https://api.tovano.ai/v1, the key and the model name.
text/demo-chat-1 costs $1.00 per million input tokens and $4.00 per million output tokens.
1. A plain request
curl https://api.tovano.ai/v1/chat/completions \
-H "Authorization: Bearer $TOVANO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "text/demo-chat-1",
"messages": [
{ "role": "system", "content": "You write short, factual product descriptions." },
{ "role": "user", "content": "Describe an insulated steel water bottle in two sentences." }
],
"max_tokens": 200
}'
The reply has the message and the token counts in usage.
2. Stream the reply
Add "stream": true. The reply arrives as server-sent events, one data: line per piece, and ends with data: [DONE]. To get the token counts and the charge, also ask for usage:
curl -N https://api.tovano.ai/v1/chat/completions \
-H "Authorization: Bearer $TOVANO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "text/demo-chat-1",
"messages": [{ "role": "user", "content": "Three captions for a mug ad" }],
"stream": true,
"stream_options": { "include_usage": true }
}'
The last chunk before [DONE] carries the usage and a tovano block with the task ID and the charge:
{
"choices": [],
"usage": { "prompt_tokens": 42, "completion_tokens": 61, "total_tokens": 103 },
"tovano": { "task_id": "tsk_c81d20a4f6e1", "charged_micro": 286 }
}
42 input tokens at $1.00 per million and 61 output tokens at $4.00 per million make $0.000286.
3. Stream with the SDK
The SDK asks for usage automatically and gives you an async iterator:
import { Tovano } from "tovano";
const tovano = new Tovano();
const stream = tovano.chat.completions.create({
model: "text/demo-chat-1",
messages: [{ role: "user", content: "Three captions for a mug ad" }],
max_tokens: 300,
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta.content ?? "");
if (chunk.usage) console.log("\n", chunk.usage);
}
4. Pass the stream to a browser
Never put your API key in browser code. Stream from your server and pass the text on:
// A route on your server, for example in Bun or any fetch-based framework.
export async function POST(req: Request) {
const { prompt } = await req.json();
const upstream = await fetch("https://api.tovano.ai/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TOVANO_API_KEY}`,
"Content-Type": "application/json",
"X-Tovano-Customer": "client-0482",
},
body: JSON.stringify({
model: "text/demo-chat-1",
messages: [{ role: "user", content: prompt }],
stream: true,
}),
});
return new Response(upstream.body, { headers: { "Content-Type": "text/event-stream" } });
}
How chat is charged
- While the request runs, the input tokens plus
max_tokensare reserved. Setmax_tokensto what you really need so less of your balance is held. - When the reply ends, you are charged for the tokens actually used and the rest is released.
- Every chat call is recorded as a task, so it shows up in Tasks and Usage with its customer tag.
- If the call fails before the model answers, nothing is charged.