Tenzro Infer — Docs
How to call the models served on the Tenzro network: access, endpoints, and the wire protocol. The API is OpenAI-compatible, so most existing clients work unchanged.
Access
Every model is gated by an API key. Requests without a valid key are rejected before any compute runs. Pass the key in the X-Tenzro-Api-Key header.
On this site the key is held server-side and never reaches the browser — the playground calls a same-origin proxy (/api/infer/*) that attaches the key and forwards to the node. Build your own integration the same way: keep the key on your server, never in client code.
inference, a requests-per-minute tier, and are read-only. Manage your own keys with tenzro key list-mine / tenzro key revoke-mine.Endpoints
The node exposes an OpenAI-compatible surface under /v1:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/chat/completions | POST | Chat (text, or text + images) |
/v1/models | GET | List models the key may reach |
Both models — qwen3.8-27b and muse-glimmer-30b — are multimodal: they take text and, optionally, one or more images, and return text. Through this site the same call is available same-origin at /api/infer/chat.
Protocol
The wire format is the OpenAI Chat Completions API. Any OpenAI SDK works — set the base URL to your node's /v1 and send the key in the header.
curl https://infer.tenzro.com/api/infer/chat \
-H "content-type: application/json" \
-d '{
"model": "qwen3.8-27b",
"messages": [{ "role": "user", "content": "Hello from Tenzro" }]
}'// The node speaks the OpenAI wire format, so any OpenAI client works.
// Point it at your node and pass the API key as X-Tenzro-Api-Key.
import OpenAI from "openai"
const client = new OpenAI({
baseURL: "https://<your-node>/v1",
apiKey: "unused", // key goes in the header below
defaultHeaders: { "X-Tenzro-Api-Key": process.env.TENZRO_API_KEY },
})
const stream = await client.chat.completions.create({
model: "qwen3.8-27b",
messages: [{ role: "user", content: "Explain NVFP4 in one line." }],
stream: true,
})
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "")
}Streaming
Set stream: true for token-by-token Server-Sent Events. Each event is a data: line carrying a JSON delta; the stream ends with data: [DONE]. Streaming is the recommended default — it is the lowest-latency path and what the playground uses.
Provenance
Every response carries a tenzro_contentProvenance block: an ed25519 signature over the content hash, the model id, and the signing node's public key, asserting ai-generated. You can verify any output came from the model that claims it, unmodified — verifiable inference, not just a black-box call.
Multimodal
Attach images by sending an array of content parts — a text part and one or more image_url parts (a data: URL or an https URL). Both models read them; the response is text.
# Multimodal: send text + an image (data URL or https URL) in one message.
curl https://infer.tenzro.com/api/infer/chat \
-H "content-type: application/json" \
-d '{
"model": "muse-glimmer-30b",
"messages": [{
"role": "user",
"content": [
{ "type": "text", "text": "What is in this image?" },
{ "type": "image_url", "image_url": { "url": "data:image/jpeg;base64,..." } }
]
}]
}'Limits
Free-tier keys are rate-limited (60 requests/minute by default). Usage is metered per token in TNZO on paid tiers; the playground runs on a gated demo key.