API reference

The API is OpenAI-compatible. If your code already talks to OpenAI, changing the base URL and the key is the whole migration. Your base URL is shown in the console alongside your keys.

Quickstart

Create a key from the console, then point any OpenAI client at the API:

quickstart.py
from openai import OpenAI

client = OpenAI(
    base_url="https://tokenkey.in/v1",
    api_key="tk_live_...",
)

response = client.chat.completions.create(
    model="tk-auto",
    messages=[{"role": "user", "content": "hello"}],
)

Authentication

Pass the key as a bearer token. Keys look like tk_live_<id>_<secret>.

header
Authorization: Bearer tk_live_...

Only a hash of the secret is stored, so a key is shown once at creation and cannot be recovered afterwards. If you lose one, revoke it and create another. Keys are issued from the console rather than through the API: a key that can mint keys means revoking a leaked one does not revoke the key it already created.

Models

ModelPurpose
tk-autoThe router chooses a tier, and looks the question up on the web first when it needs current information. Recommended default. Any chat request can ask for a search with "web_search": true.
tk-baseFast tier, for short high-volume requests.
tk-reasonReasoning tier: thinks before it answers. Worth the wait for maths, logic and multi-step problems; slower than tk-base for everything else.
tk-coderCode generation and repository-scale edits. Coming shortly — not yet serving requests.

TokenKey answers in English. Ask in another language and your question is still answered, in English, with a line saying other languages are not supported yet. Translation itself is declined rather than attempted: it is not reliable on this deployment yet.

Naming a model explicitly always wins — the router never second-guesses an explicit choice. Which tier served a request, and why, is recorded and visible in the console.

The available models can change. Call GET /v1/models for the authoritative list.

Using TokenKey in AI clients

Desktop chat apps, editor extensions and terminal agents mostly speak the OpenAI API, so they work here unchanged. Whatever the client calls its fields, it is asking for the same three values:

Base URLhttps://tokenkey.in/v1
API keytk_live_...
Modeltk-auto, tk-base or tk-reason

Some clients ask for a base URL that already ends in /v1 and others append it themselves. If a connection test fails, that is the first thing to check. Three worked examples:

Chatbox

Desktop and web

  1. Settings, bottom left, then Model Provider and Add.
  2. Choose API type OpenAI API Compatible, then fill in the name TokenKey, your key, and the API host https://tokenkey.in/v1. Leave the API path at its default of /chat/completions.
  3. Under Model, choose New, add tk-base, and save.
  4. Press Check. It should report a successful connection.
  5. Pick TokenKey from the model dropdown in a chat.

Cline

VS Code extension

  1. Open the Cline panel and its settings icon.
  2. Set API Provider to OpenAI Compatible.
  3. Base URL https://tokenkey.in/v1, your key, and model ID tk-base — or tk-auto or tk-reason.

opencode

Terminal agent

  1. Declare the provider in ~/.config/opencode/opencode.jsonc:
    opencode.jsonc
    {
      "$schema": "https://opencode.ai/config.json",
      "provider": {
        "tokenkey": {
          "npm": "@ai-sdk/openai-compatible",
          "name": "TokenKey",
          "options": { "baseURL": "https://tokenkey.in/v1" },
          "models": {
            "tk-auto": { "name": "TokenKey auto" },
            "tk-base": { "name": "TokenKey fast" },
            "tk-reason": { "name": "TokenKey reasoning" }
          }
        }
      }
    }
  2. Add the key from inside opencode: /connect, then Other, provider id tokenkey, then paste it.
  3. Choose the model with /models, then TokenKey, then tk-auto.
  4. Send a test message. Restart opencode if you edited the config after it was already running.

Agent tools that run for a long time are better pointed at tk-base than tk-auto: the router may send a hard question to the reasoning tier, which thinks before it answers and is slower per step.

Streaming

Set stream: true for server-sent events. Token usage is captured whether or not you ask for it — if you do not set stream_options.include_usage, the gateway requests it internally and strips the extra chunk before it reaches you, so you receive exactly the stream you asked for.

stream.py
stream = client.chat.completions.create(
    model="tk-auto",
    messages=[{"role": "user", "content": "explain gradient descent"}],
    stream=True,
)

for chunk in stream:
    print(chunk.choices[0].delta.content or "", end="")

Disconnecting mid-stream cancels the generation upstream rather than leaving it running, and what was consumed up to that point is still recorded.

Rate limits

Two limits apply: requests per minute, enforced on arrival, and tokens per minute plus a daily cap, reconciled after each response. A request’s cost is not known until it finishes, so one call may overshoot the token window and the next is refused rather than the current one being cut off.

Every response carries the current state:

response headers
x-ratelimit-limit-requests: 1000
x-ratelimit-remaining-requests: 987
x-ratelimit-reset-requests: 60

A 429 includes Retry-After in seconds. Your exact limits are on the settings page in the console.

Errors

Errors use the OpenAI shape, so SDK error handling works unchanged.

error body
{
  "error": {
    "message": "The model 'gpt-4o' does not exist. Available models: ...",
    "type": "invalid_request_error",
    "param": "model",
    "code": "model_not_found"
  }
}
StatusCodeMeaning
401invalid_api_keyMissing, malformed, revoked or expired key.
404model_not_foundThe model is not in the registry. The message lists what is.
400tier_unavailableThe tier this request needs is not available — sending images to a text-only service, for example.
429rate_limit_exceededRequest or token quota exceeded. Honour the Retry-After header.
502api_errorThe inference backend could not be reached.

Data handling

Prompt and completion text is not stored. Usage records hold token counts, latency, the model requested and the tier that served it — nothing else. Inference runs on hardware in Amaravati, Andhra Pradesh, India, so your text is not forwarded to a model provider abroad.

This is asserted by a test that sends a marker string through streamed and non-streamed completions and then scans every column of every table for it. It runs on every commit, which is how the guarantee survives future changes.