Docs

An OpenAI-compatible endpoint,
and a bill you can recompute

Point your existing SDK at our base URL and change the key. Everything on this page is the contract: the same prices, the same multiplier and the same usage fields we bill from.

Status of each surface

api.tokentoken.aiPrivate preview
app.tokentoken.ai consolePrivate preview
Published prices & rateLive
Skill filesLive

Honest status, not a roadmap promise. See the notice below.

Read this before you wire anything up

The inference API is not open for self-service yet. Today https://api.tokentoken.ai answers every path with 503 and a JSON body saying so — it is reserved, not running. The endpoints below are the contract we are building to, published early so you can review it, estimate cost and tell us what is missing.

If you are an existing relay customer (the New API service), your base URL is https://tokenindex.ai/v1 and your existing sk- key is unchanged. That service is separate from this one: different accounts, different balance, different upstreams.

Want access when it opens? sales@cflabs.ai — tell us the models and the rough monthly volume.

1 · Base URL and authentication

One bearer token on every request. Keys are shown once at creation and stored only as a hash, so we cannot recover one for you — rotate instead.

POST https://api.tokentoken.ai/v1/chat/completions
Authorization: Bearer tt-...
Content-Type: application/json

Key prefix

Every key starts with tt-. The console shows the prefix and the creation date, never the secret.

What a key carries

A model allowlist, a spend cap, RPM/TPM, a concurrency limit, an expiry and an optional IP allowlist. All enforced server-side.

Scope

Keys belong to an organization, not a person. Revoking a key never touches the balance or the other keys.

2 · Your first request

The wire format is OpenAI's. Any client that can take a base URL works unchanged — the official openai SDKs, LangChain, LlamaIndex, Codex CLI, Cline, Aider.

curl

curl https://api.tokentoken.ai/v1/chat/completions \
  -H "Authorization: Bearer $TOKENTOKEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "tt/kimi-k3.1-pro",
    "messages": [{"role": "user", "content": "Say hello in five words."}],
    "max_tokens": 64
  }'

Python

from openai import OpenAI

client = OpenAI(
    base_url="https://api.tokentoken.ai/v1",
    api_key=os.environ["TOKENTOKEN_API_KEY"],
)

resp = client.chat.completions.create(
    model="tt/kimi-k3.1-pro",
    messages=[{"role": "user", "content": "Say hello in five words."}],
    max_tokens=64,
)
print(resp.choices[0].message.content)
print(resp.id)            # keep this: it is the id on your invoice line

Node

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.tokentoken.ai/v1",
  apiKey: process.env.TOKENTOKEN_API_KEY,
});

const resp = await client.chat.completions.create({
  model: "tt/kimi-k3.1-pro",
  messages: [{ role: "user", content: "Say hello in five words." }],
  max_tokens: 64,
});

Streaming: pass stream: true. You do not need stream_options for usage — we obtain usage from the upstream ourselves, so billing never depends on the client asking for it.

3 · Model ids

Self-hosted routes are prefixed tt/. A pinned id keeps serving the same weights, the same quantization and the same context window — we do not silently upgrade the thing behind an id. A new revision gets a new id.

FieldMeaning
idWhat you send in model.
source_labelWhere it runs: own_gpu, official, cloud, licensed_third_party. Returned on every response, not just in the catalogue.
contextMaximum context window in tokens.
quantizationThe exact weight format being served.

The full catalogue and prices llms.txt (machine-readable)

4 · How the charge is computed

Prices are published per million tokens. The charge for one call is an exact integer computation — we do not use floating point anywhere in the billing path, and we do not use the gateway's own cost estimate, because it ignores cache discounts.

charge = round_half_up(
    ( prompt_uncached × input_price
    + cached_tokens   × cache_read_price
    + completion      × output_price ) × rate
)

Cached tokens are discounted

prompt_tokens includes cache hits. We subtract cached_tokens and price those at the cache-read rate, so a cache hit is never billed at full input price.

One charge per call

If we retry an upstream or fail over to another route, you are charged once, for the attempt that succeeded. The failed attempts are our cost, not yours.

rate is one public number

Currently 1.00. GET /v1/pricing returns it with a version, and every invoice line records the version it was billed at. Changing it never reprices history.

Reading your usage back

GET /v1/pricing                  → { rate, rate_version, currency, models: [...] }
GET /v1/usage?from=&to=          → one row per call: request_id, model, tokens, charge, rate_version
GET /v1/credits                  → { balance, currency, as_of }

Every row carries the request_id that the API returned, so any line on an invoice can be traced back to the call that produced it.

5 · Errors

Error bodies are OpenAI-shaped: {"error":{"type","code","message"}}. The codes below are ours and are stable.

StatuscodeWhat it means and what to do
401invalid_api_keyUnknown, revoked or expired key. Not retryable.
402insufficient_creditsBalance below the estimated cost of this call. Nothing was reserved and nothing was charged. Top up, then retry.
403model_not_allowedThe model is not on this key's allowlist.
403ip_not_allowedSource IP outside this key's allowlist.
400parameter_out_of_rangeA billable multiplier exceeded its cap — max_tokens, image n, video seconds, batch size. Caps exist so a bad value cannot produce a runaway charge.
429rate_limitedThis key's RPM, TPM or concurrency limit. Honour Retry-After.
502upstream_failedAll routes for this model failed. The reservation was released; you were not charged.
503not_launchedWhat the API returns today. See the notice at the top of this page.

If your client disconnects mid-stream, the tokens already produced upstream are real and are billed; the record is marked client_disconnected so you can find it.

For agents

Machine-readable catalogue, installable skill files, and per-key limits an agent cannot talk its way around because we enforce them server-side.

Skills & agent setup llms.txt

Questions this page did not answer

support@cflabs.ai for integration questions, sales@cflabs.ai for access and volume, security@cflabs.ai for anything security-related. Data handling, retention and attestation are on the Trust page.