Tenzro Labs
Tutorial 02 · Model API

Embeddings, forecasts and images

Language models are one kind. The same key calls embedding, forecasting and image models, each at its own endpoint.
Step 01

Find each model's endpoint

Each model kind is called differently, so each has its own endpoint. The modality and endpoint fields from GET https://api.tenzro.xyz/v1/models tell you which one a model uses.

Language
POST /v1/chat/completions
Embeddings
POST /v1/embeddings
Forecasting
POST /v1/forecasts
Image generation
POST /v1/images/generations
shell
curl -s https://api.tenzro.xyz/v1/models | jq -r '.data[] | "\(.id)  \(.modality)  \(.endpoint)"'

Calling a model at the wrong endpoint returns 400 wrong_endpoint, and the message names the right one. Every endpoint takes the optional machine field, defaulting to tenzro-partner-cluster.

Step 02

Embed texts

/v1/embeddings is OpenAI-compatible. Vectors are unit length, so cosine similarity is a dot product.

model
string
Required. An embedding model id.
input
string | string[]
Required. Up to 256 texts per request.
dimensions
integer
Optional. A shorter vector where the model supports it: 1024, 768, 512, 256, 128, 64 or 32 for Qwen3-Embedding 0.6B.
input_type
"document" | "query"
Optional. query for search queries, document for everything else (the default).
machine
string
Optional. Defaults to tenzro-partner-cluster.
shell
curl https://api.tenzro.xyz/v1/embeddings \
  -H "Authorization: Bearer $TENZRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "qwen3-embedding-0.6b", "input": ["Tenzro settles in TNZO", "What does Tenzro settle in?"]}'
response
{
  "object": "list",
  "model": "qwen3-embedding-0.6b",
  "data": [{ "object": "embedding", "index": 0, "embedding": [0.0123, -0.0456, ...] }],
  "usage": { "prompt_tokens": 12, "total_tokens": 12 }
}

Search with Python

Embed the passages as documents and the question as a query, then rank by dot product.

python
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.tenzro.xyz/v1", api_key=os.environ["TENZRO_API_KEY"])
MODEL = "qwen3-embedding-0.6b"

passages = [
    "TNZO is the gas, staking and settlement token of the Tenzro Network.",
    "Operators serve models from their machines on the network.",
    "Cortex is the Tenzro Labs assistant for people.",
]
docs = client.embeddings.create(model=MODEL, input=passages, dimensions=512)
query = client.embeddings.create(
    model=MODEL,
    input="Which token settles payments?",
    dimensions=512,
    extra_body={"input_type": "query"},
)

q = query.data[0].embedding
scores = [sum(a * b for a, b in zip(q, d.embedding)) for d in docs.data]
best = max(range(len(passages)), key=lambda i: scores[i])
print(passages[best])
Step 03

Forecast a time series

Send a series, oldest value first, and how many steps to forecast. Quantiles give an uncertainty band around the point forecast.

model
string
Required. A forecasting model id.
history
number[]
Required. At least two values, oldest first. The model uses up to its history limit.
horizon
integer
Required. Steps ahead, up to the model's horizon limit.
quantiles
number[]
Optional. Levels between 0 and 1, for example [0.1, 0.5, 0.9].
frequency_seconds
integer
Optional. The spacing of the series, when it is regular.
machine
string
Optional. Defaults to tenzro-partner-cluster.
shell
curl https://api.tenzro.xyz/v1/forecasts \
  -H "Authorization: Bearer $TENZRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "timesfm-2.5-200m", "history": [112, 118, 132, 129, 121, 135, 148, 148, 136, 119], "horizon": 6, "quantiles": [0.1, 0.5, 0.9]}'
response
{
  "object": "forecast",
  "model": "timesfm-2.5-200m",
  "history_used": 10,
  "point": [141.2, 137.9, 139.4, 144.0, 146.1, 143.3],
  "quantile_levels": [0.1, 0.5, 0.9],
  "quantiles": [[128.4, ...], [141.2, ...], [155.0, ...]],
  "generation_time_ms": 84
}

quantiles holds one row per level in quantile_levels, each as long as the horizon.

Python

python
import os, requests

series = [112, 118, 132, 129, 121, 135, 148, 148, 136, 119]
r = requests.post(
    "https://api.tenzro.xyz/v1/forecasts",
    headers={"Authorization": f"Bearer {os.environ['TENZRO_API_KEY']}"},
    json={"model": "timesfm-2.5-200m", "history": series, "horizon": 6, "quantiles": [0.1, 0.9]},
)
r.raise_for_status()
forecast = r.json()
low, high = forecast["quantiles"]
for step, (p, lo, hi) in enumerate(zip(forecast["point"], low, high), start=1):
    print(f"t+{step}: {p:.1f}  ({lo:.1f} to {hi:.1f})")

JavaScript

javascript
const res = await fetch("https://api.tenzro.xyz/v1/forecasts", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.TENZRO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "timesfm-2.5-200m",
    history: [112, 118, 132, 129, 121, 135, 148, 148, 136, 119],
    horizon: 6,
    quantiles: [0.1, 0.5, 0.9],
  }),
});
const forecast = await res.json();
console.log(forecast.point);
Step 04

Generate an image

The image endpoint is live and routes like the others. While no image model is serving, it answers 503 no_capacity. The models list shows when one is serving.

shell
curl https://api.tenzro.xyz/v1/images/generations \
  -H "Authorization: Bearer $TENZRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "flux2-klein-4b", "prompt": "a lighthouse at dawn, watercolour"}'
shell · is an image model serving?
curl -s https://api.tenzro.xyz/v1/models | jq '.data[] | select(.modality == "image") | .id'
Step 05

Know what each call costs

Language
Input and output tokens
Embeddings
Input tokens
Forecasting
Per request
Image generation
Per request

Charges come from your credits after the call completes, or are covered by the rental or subscription the key belongs to. Credits are Tenzro Labs credits: 1 credit is 0.001 TNZO.

Every price is zero on testnet, and a free model needs no balance. A priced model called with an empty balance returns 402 insufficient_credit.