Invitation-only AI inference

Tokenaro

An AI server with OpenAI- and Anthropic-compatible APIs. Six models cover chat, coding, reasoning, image input, document OCR, speech-to-text, text-to-speech and real-time voice, all at one address. Using them takes a personal API key from the server's owner; this page shows how to connect once you have one.

API base URL
https://api.tokenaro.ai/v1

Use it anywhere an app asks for an “OpenAI base URL”. Anthropic-format clients take https://api.tokenaro.ai, without /v1. Send your key as Authorization: Bearer <key> or x-api-key: <key>.

Paste the key you were given. It is placed into every command, settings snippet and agent prompt on this page. It stays in this browser tab: it is not saved, and this page never sends it anywhere.

No key entered. Commands and prompts show YOUR_TOKENARO_KEY instead.

01 · Getting started

Three steps

  1. Get your key

    There is no sign-up: the server's owner gives each person their own API key, so ask the person who invited you. Each key has its own model list and limits and can be revoked, so don't share yours. Paste it into the key box above, and the commands below will use it.

  2. Check that it works

    Save the key in an environment variable once. The examples on this page read it from there.

    bash / zsh
    export TOKENARO_API_KEY="YOUR_TOKENARO_KEY"
    curl https://api.tokenaro.ai/v1/models -H "Authorization: Bearer $TOKENARO_API_KEY"
    PowerShell
    $env:TOKENARO_API_KEY = "YOUR_TOKENARO_KEY"
    curl.exe https://api.tokenaro.ai/v1/models -H "Authorization: Bearer $env:TOKENARO_API_KEY"

    The reply lists the models your key can use.

  3. Connect your app or agent

    In any OpenAI- or Anthropic-compatible app, enter the base URL, your key and a model id. For an AI agent, open Agent setup: each agent has numbered steps to do it yourself, and a prompt you can paste into the agent's chat instead, so it changes its own settings, tests the connection and reports back.

02 · Models

Six models, one API

Each model runs on its own service, and that service runs nothing else. Choose the model with the request's model field.

Models available on Tokenaro
Model idWhat it's forIn → outContextEndpoint
qwen3.8-27bmain The main model, and your default choice. Strong at general chat, coding, tool calls and image input. It is a reasoning model. text, image → text 262K /v1/chat/completions (streaming)
deepseek-v4.1-flashslow A very large model that runs on CPU. It gives the best answers on hard questions, but it is slow. Use it when quality matters more than waiting. It is a reasoning model, so stream it. text → text 1M /v1/chat/completions
lfm3-audio-2bfast A small, very fast model that handles audio natively. Use it for quick helper jobs (titles, short summaries, classification) and for voice. It supports tool calls, but it is not for agentic coding. text, audio → text, speech 128K /v1/chat/completions, wss://…/v1/realtime
glm-ocr Document OCR. Send a page image and get back the text as Markdown, including tables and formulas. image → text 128K /v1/chat/completions
granite-speech-5.0-2b Speech-to-text (transcription). audio → text 16K /v1/audio/transcriptions
chatterbox-turbo Text-to-speech with natural English and one built-in voice. The voice field is accepted but ignored. text → speech 8K /v1/audio/speech
Not sure? Use qwen3.8-27b.
Need it fast? Use lfm3-audio-2b for short, simple jobs.
Need the best answer? Use deepseek-v4.1-flash, stream the reply and be patient.

Not available: embeddings, image generation, fine-tuning, and the files, batches and assistants APIs.

03 · Endpoints

Endpoints and examples

Tokenaro speaks two formats with the same keys and models: OpenAI's (every endpoint below except /v1/messages) and Anthropic's Messages API. The official SDKs work once you change the base URL: https://api.tokenaro.ai/v1 for OpenAI, https://api.tokenaro.ai for Anthropic. Send your key as Authorization: Bearer <key> or x-api-key: <key>. The examples read it from TOKENARO_API_KEY (see step 2).

Endpoints
EndpointModelsNotes
GET /v1/models—Lists the models your key may use.
POST /v1/chat/completionsqwen3.8-27b, deepseek-v4.1-flash, lfm3-audio-2b, glm-ocrmessages, max_tokens, stream, tools. Content parts: image_url (qwen, glm-ocr) and input_audio (lfm3).
POST /v1/completionsqwen3.8-27b, deepseek-v4.1-flash, lfm3-audio-2bOpenAI's older Completions API: a plain prompt instead of messages.
POST /v1/responsesqwen3.8-27b, deepseek-v4.1-flash, lfm3-audio-2bOpenAI's Responses API (input, max_output_tokens, stream), for clients such as Codex that use it instead of Chat Completions.
POST /v1/messages
POST /v1/messages/count_tokens
qwen3.8-27b, deepseek-v4.1-flash, lfm3-audio-2bAnthropic's Messages API (streaming, tool use), for Claude Code and the Anthropic SDKs. Their base URL is https://api.tokenaro.ai, without /v1.
POST /v1/audio/transcriptionsgranite-speech-5.0-2bMultipart form with the audio in field file. response_format: json or verbose_json.
POST /v1/audio/speechchatterbox-turboinput up to 4,096 characters. response_format: mp3 (default), opus, aac, flac, wav or pcm. speed: 0.25–4.
WSS /v1/realtime?model=lfm3-audio-2blfm3-audio-2bReal-time voice over WebSocket using the OpenAI Realtime (GA) protocol. Send the key in the Authorization: Bearer header.

Examples

Example language

A normal chat request. Reasoning models return their thinking in reasoning_content and the answer in content. Give max_tokens some headroom.

curl
curl https://api.tokenaro.ai/v1/chat/completions \
  -H "Authorization: Bearer $TOKENARO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3.8-27b",
    "max_tokens": 2048,
    "messages": [{"role": "user", "content": "Give me three names for a grey cat."}]
  }'
Python · pip install openai
import os
from openai import OpenAI

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

r = client.chat.completions.create(
    model="qwen3.8-27b",
    max_tokens=2048,  # reasoning model: leave room for its thinking
    messages=[{"role": "user", "content": "Give me three names for a grey cat."}],
)
msg = r.choices[0].message
print(msg.content)
# The thinking, if you want it: getattr(msg, "reasoning_content", None)
JavaScript (Node) · npm install openai
import OpenAI from "openai";

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

const r = await client.chat.completions.create({
  model: "qwen3.8-27b",
  max_tokens: 2048, // reasoning model: leave room for its thinking
  messages: [{ role: "user", content: "Give me three names for a grey cat." }],
});
console.log(r.choices[0].message.content);
// The thinking, if you want it: r.choices[0].message.reasoning_content

04 · Agent setup

Connect your AI agent

Each tab gives you two ways. Follow the numbered steps to set it up yourself, or copy the prompt into your agent's chat: the agent backs up its config, adds Tokenaro as a provider, tests each model and reports what it changed and how to undo it. Enter your key first, and the snippets and prompts will contain it.

Pasting a prompt that contains your key puts the key in that agent's chat history. If you'd rather not, set it up yourself, or leave the key box empty: the agent will then ask you to put the key into its secrets file yourself.

For Hermes Agent by Nous Research. Main model and vision go to qwen3.8-27b, short helper jobs to lfm3-audio-2b, voice input to granite-speech-5.0-2b and voice output to chatterbox-turbo.

Set it up yourself

  1. Back up your settings:

    bash / zsh
    cp ~/.hermes/config.yaml ~/.hermes/config.yaml.bak-tokenaro
    [ -f ~/.hermes/.env ] && cp ~/.hermes/.env ~/.hermes/.env.bak-tokenaro
  2. Add these lines to ~/.hermes/.env (create it if needed, then chmod 600 ~/.hermes/.env). The last three are for voice. If VOICE_TOOLS_OPENAI_KEY already holds a real OpenAI key, this moves your voice features to Tokenaro.

    ~/.hermes/.env
    TOKENARO_API_KEY=YOUR_TOKENARO_KEY
    VOICE_TOOLS_OPENAI_KEY=YOUR_TOKENARO_KEY
    STT_OPENAI_BASE_URL=https://api.tokenaro.ai/v1
    STT_OPENAI_MODEL=granite-speech-5.0-2b
  3. In ~/.hermes/config.yaml, set these blocks. Keep the other keys already in them, and leave the other auxiliary tasks alone. Key names differ between Hermes versions, so check yours with hermes config check.

    ~/.hermes/config.yaml
    model:
      provider: custom
      base_url: https://api.tokenaro.ai/v1
      key_env: TOKENARO_API_KEY
      default: qwen3.8-27b
      context_length: 262144
    
    auxiliary:
      vision:              # images: must be qwen3.8-27b
        base_url: https://api.tokenaro.ai/v1
        api_key: ${TOKENARO_API_KEY}
        model: qwen3.8-27b
      compression:         # long input: needs the big context
        base_url: https://api.tokenaro.ai/v1
        api_key: ${TOKENARO_API_KEY}
        model: qwen3.8-27b
      session_search:      # long input
        base_url: https://api.tokenaro.ai/v1
        api_key: ${TOKENARO_API_KEY}
        model: qwen3.8-27b
      title_generation:    # quick text helper
        base_url: https://api.tokenaro.ai/v1
        api_key: ${TOKENARO_API_KEY}
        model: lfm3-audio-2b
      web_extract:         # quick text helper
        base_url: https://api.tokenaro.ai/v1
        api_key: ${TOKENARO_API_KEY}
        model: lfm3-audio-2b
  4. For voice, also set these blocks in the same file:

    ~/.hermes/config.yaml
    stt:
      enabled: true
      provider: openai
      streaming: false     # no live partial transcripts on Tokenaro
      openai:
        model: granite-speech-5.0-2b
    
    tts:
      provider: openai
      openai:
        base_url: https://api.tokenaro.ai/v1
        model: chatterbox-turbo
        voice: alloy       # ignored: there is one built-in voice
  5. Restart Hermes (and hermes gateway, if you run it) and send it a message; qwen3.8-27b now answers. With voice set up, try /voice on, /voice tts, then ask “What's two plus two?”.

Undo: cp ~/.hermes/config.yaml.bak-tokenaro ~/.hermes/config.yaml, the same for ~/.hermes/.env, then restart Hermes. Moving from the old “Darknight” setup (Tailscale IP, separate ports, local TTS shim)? The prompt below also removes those leftovers.

Or let your agent do it

Paste this into Hermes's chat. It makes the same changes, tests every model, and reports back.

Prompt for Hermes Agent
# Task: connect yourself (Hermes Agent) to Tokenaro

Tokenaro is a private, OpenAI-compatible AI server. It replaces the old "Darknight" server: no Tailscale IP, no separate ports, no local TTS shim. Everything now goes through one HTTPS address with a personal API key. Reconfigure yourself to use it, test it, and report back. Work through the steps in order.

## Connection
- Base URL: https://api.tokenaro.ai/v1  (all models and endpoints)
- API key: YOUR_TOKENARO_KEY
- Auth header: "Authorization: Bearer <key>" ("x-api-key: <key>" also works). HTTP 401 = wrong or revoked key. HTTP 403 = no key sent (blocked at the edge) or a model not on this key. HTTP 429 = this key's limits were hit (simultaneous requests or requests/minute): wait and retry.

## Models (exact ids)
- qwen3.8-27b: your main model AND your vision model. Chat, coding, tool calls, image input. Reasoning model. Context 262,144 tokens.
- lfm3-audio-2b: small, very fast helper for short text jobs (titles, short summaries, classification). Context 128,000 tokens. Not for coding.
- deepseek-v4.1-flash: very large and slow (runs on CPU). Only for hard questions nobody is waiting on. Context 1,048,576 tokens. Never use it for voice or as an auxiliary model.
- granite-speech-5.0-2b: speech-to-text, POST /v1/audio/transcriptions.
- chatterbox-turbo: text-to-speech, POST /v1/audio/speech (OpenAI format; one built-in English voice, "voice" is ignored; mp3 by default).
- glm-ocr: document OCR (page image as an image_url part plus the text "Text Recognition:").

## Rules
1. Back up before editing anything:
   cp ~/.hermes/config.yaml ~/.hermes/config.yaml.bak-tokenaro
   [ -f ~/.hermes/.env ] && cp ~/.hermes/.env ~/.hermes/.env.bak-tokenaro
2. The key is a secret. Never print or echo it, and never put it in a log, a commit or our chat. It lives only in ~/.hermes/.env; config.yaml refers to it as ${TOKENARO_API_KEY}. When you show me config, mask it (sk-...last 4). If the key under "Connection" still reads YOUR_TOKENARO_KEY, ask me to add it to ~/.hermes/.env myself.
3. Change only what this task names. Key names differ between Hermes versions: before writing YAML, check yours (`hermes config`, `hermes config check`, and cli-config.yaml.example in your install) and adapt the examples below. Don't invent keys.
4. Reasoning models return their thinking in reasoning_content and the answer in content. Leave max_tokens headroom (1024+ even for a one-word answer, 4096+ for real work). Empty content with finish_reason "length" means the budget ran out.
5. A request that sends nothing for 100 s is cut off (HTTP 524), so long generations must stream.

## Step 1: Secrets in ~/.hermes/.env (chmod 600)
TOKENARO_API_KEY=YOUR_TOKENARO_KEY
VOICE_TOOLS_OPENAI_KEY=YOUR_TOKENARO_KEY
STT_OPENAI_BASE_URL=https://api.tokenaro.ai/v1
STT_OPENAI_MODEL=granite-speech-5.0-2b
(VOICE_TOOLS_OPENAI_KEY is the key Hermes's openai STT and TTS providers send. If it currently holds a real OpenAI key, ask me before replacing it.)

## Step 2: Remove the old Darknight setup, if present
grep -rn -E '100\.110\.46\.112|darknight|:808[1-7]|127\.0\.0\.1:8099|k2-horizon|gemma-4-e4b' ~/.hermes/config.yaml ~/.hermes/.env ~/.hermes/skills 2>/dev/null
Every hit is stale: replace it with the settings below, or delete it. The local TTS shim is no longer needed:
systemctl --user disable --now darknight-tts-shim 2>/dev/null
then delete ~/.config/systemd/user/darknight-tts-shim.service and ~/.hermes/darknight_tts_shim.py, and run `systemctl --user daemon-reload`.

## Step 3: ~/.hermes/config.yaml
model:
  provider: custom
  base_url: https://api.tokenaro.ai/v1
  key_env: TOKENARO_API_KEY
  default: qwen3.8-27b
  context_length: 262144

auxiliary:
  vision:              # images: must be qwen3.8-27b
    base_url: https://api.tokenaro.ai/v1
    api_key: ${TOKENARO_API_KEY}
    model: qwen3.8-27b
  compression:         # long input: needs the big context
    base_url: https://api.tokenaro.ai/v1
    api_key: ${TOKENARO_API_KEY}
    model: qwen3.8-27b
  session_search:      # long input
    base_url: https://api.tokenaro.ai/v1
    api_key: ${TOKENARO_API_KEY}
    model: qwen3.8-27b
  title_generation:    # quick text helper
    base_url: https://api.tokenaro.ai/v1
    api_key: ${TOKENARO_API_KEY}
    model: lfm3-audio-2b
  web_extract:         # quick text helper
    base_url: https://api.tokenaro.ai/v1
    api_key: ${TOKENARO_API_KEY}
    model: lfm3-audio-2b

stt:
  enabled: true
  provider: openai
  streaming: false     # no live partial transcripts on Tokenaro
  openai:
    model: granite-speech-5.0-2b

tts:
  provider: openai
  openai:
    base_url: https://api.tokenaro.ai/v1
    model: chatterbox-turbo
    voice: alloy       # ignored: there is one built-in voice

Keep the other keys already in those blocks (timeouts, enabled flags and so on), and leave the other auxiliary tasks alone. If web_extract fails because a page is too long for lfm3-audio-2b's 128K window, move web_extract to qwen3.8-27b.

## Step 4: Test one call per model (the key is read from .env, never shown)
export TOKENARO_API_KEY="$(grep -m1 '^TOKENARO_API_KEY=' ~/.hermes/.env | cut -d= -f2-)"
U=https://api.tokenaro.ai/v1; H="Authorization: Bearer $TOKENARO_API_KEY"
# a) the key works; prints the models it may use
curl -sS "$U/models" -H "$H" | python3 -c 'import json,sys; print([m["id"] for m in json.load(sys.stdin)["data"]])'
# b) chat with both text models (expect "OK" twice)
for M in qwen3.8-27b lfm3-audio-2b; do
  curl -sS "$U/chat/completions" -H "$H" -H 'Content-Type: application/json' \
    -d "{\"model\":\"$M\",\"max_tokens\":1024,\"messages\":[{\"role\":\"user\",\"content\":\"Reply with just OK\"}]}" \
    | python3 -c 'import json,sys; r=json.load(sys.stdin); print(r["choices"][0]["message"]["content"] if "choices" in r else r)'
done
# c) text-to-speech (expect an MP3 file)
curl -sS "$U/audio/speech" -H "$H" -H 'Content-Type: application/json' \
  -d '{"model":"chatterbox-turbo","voice":"alloy","input":"Hello from Tokenaro."}' -o /tmp/tokenaro-test.mp3 && file /tmp/tokenaro-test.mp3
# d) speech-to-text of that file (expect about "Hello from Tokenaro.")
curl -sS "$U/audio/transcriptions" -H "$H" -F model=granite-speech-5.0-2b -F file=@/tmp/tokenaro-test.mp3 -F response_format=json
Then restart Hermes (and `hermes gateway`, if you run it) so the new config loads. Answer one message on the new setup. If voice is enabled, also do a spoken round trip: /voice on, /voice tts, then ask "What's two plus two?".

## Step 5: Report back
- What you changed: files, config sections, .env variable names (key masked), and the stale Darknight entries you removed.
- Every test: pass or fail, with a short excerpt of the output or the error.
- Anything that needed me (sudo, a decision about an existing key).

## How to undo
cp ~/.hermes/config.yaml.bak-tokenaro ~/.hermes/config.yaml
cp ~/.hermes/.env.bak-tokenaro ~/.hermes/.env    # if you backed it up
Then restart Hermes.

Checked against the Hermes Agent docs (configuration, providers) on 2026-10-29.

05 · Limits & tips

Limits and tips

  • Your key has limits. Each key has a cap on simultaneous requests and on requests per minute. Going over either returns HTTP 429. Wait a moment and retry, ideally with backoff.
  • Key errors. A request with no key at all is refused at the edge with HTTP 403. A key that is wrong or has been revoked gets 401, and a model that isn't on your key's list gets 403.
  • Stream long answers. Cloudflare drops a request that sends nothing for 100 seconds and returns HTTP 524. Use "stream": true for anything long, and always for deepseek-v4.1-flash.
  • Reasoning models need room. qwen3.8-27b and deepseek-v4.1-flash think before they answer. The thinking comes back in reasoning_content, separate from content. If max_tokens runs out while the model is still thinking, content is empty and finish_reason is "length". Raise the limit: 1,024 or more even for short answers.
  • Always send model. Requests are routed by the model id, and your key only works with the models on its list (GET /v1/models).
  • Size limits. A request body can be at most 100 MB, so downscale big images and split long recordings. Text-to-speech takes up to 4,096 characters per request.
  • Privacy. The server does not store prompts or outputs. It keeps only usage counts per key.
  • Keep your key private. Keep it on your machine or server, never in a web page or a public repository. If it leaks, ask for it to be revoked.

Capacity

How many people each model can serve at the same time, and the speed one person typically sees. These numbers are still being measured.

Capacity per model
ModelSimultaneous usersTypical speed per user
qwen3.8-27b——
deepseek-v4.1-flash——
lfm3-audio-2b——
glm-ocr——
granite-speech-5.0-2b——
chatterbox-turbo——

Figures marked — haven't been measured yet.

06 · Help

Need a key, or something's wrong?

Ask the person who gave you your key. That applies to a new key, more models on your key, higher limits, and anything that's broken. Tokenaro has no sign-up: if you don't have a key yet, ask the person who invited you.

When something fails, tell them the time it happened, the model, and the HTTP status or error message. Never send the key itself; they can identify your key without it.