Curated models for your best work

Join the waitlist

Router docs

Requests and auth

How to authenticate against the rail and what a request may carry.

Authentication

Use a rail key (tsr_...) from Router. Either header form works.

Headers
x-api-key: tsr_...
# or
Authorization: Bearer tsr_...

Keys are stored hashed, shown once at creation, and revoke instantly (no cache in the auth path).

Use only a TokenSpend rail key, not a provider, Capture, or admin credential. Keep keys server-side and out of source control. Your workspace needs an eligible connected provider key or managed credits.

Endpoints

Base URL https://api.tokenspend.dev

  • POST /v1/chat/completions: OpenAI Chat Completions
  • POST /v1/responses: Responses, with native Astra tools
  • POST /v1/messages: Anthropic Messages
  • POST /v1/messages/count_tokens: supported Messages models
  • GET /v1/health
  • GET /v1/models: canonical model contracts
  • GET /v1/receipts: receipts of the calling key

Chat Completions and Messages support text, system prompts, streaming, function tools, and model-approved images. Validated structured output is available only where the registry marks the selected protocol. A field that cannot survive translation returns 400 with its exact path.

Request contract

Standard fields pass through when the selected model can honor them. Cross-format requests support the shared text, sampling, stop, stream, and function-tool controls. Inexact controls are rejected, never discarded.

  • The provider object chooses a provider (below). Other routing blocks are unsupported.
  • Unproven translated reasoning and structured-output controls return 400.
  • Cross-format requests without a token limit use a 4,096-token maximum.
  • Unknown consequential fields return 400 with error.param.
  • Malformed JSON and request shapes return 400 before routing.

Choosing a provider

By default TokenSpend picks the cheapest working provider for you, and tries one more if the first returns an error or stalls. To choose instead, add a provider object. Each model page lists the providers that can run it, with the slug to use.

curl
curl https://api.tokenspend.dev/v1/chat/completions \
  -H "Authorization: Bearer $TOKENSPEND_API_KEY" \
  -H "content-type: application/json" \
  -d '{
    "model": "moonshot/kimi-k3",
    "messages": [{"role": "user", "content": "Hello"}],
    "provider": {"only": ["novita"], "allow_fallbacks": false}
  }'
  • only runs the request on these providers and no others.
  • order tries these first, in this order. The rest stay as fallbacks.
  • allow_fallbacks: false makes one attempt: no second provider and no model fallback. A failure comes back as a TokenSpend error. With order, the providers you did not list are dropped.

Where adding a body field is awkward, send the header x-tokenspend-provider: novita,baseten, which means only. Choosing any provider also turns off a configured model fallback for that request. Both TokenSpend SDKs take a provider option, where a string or a list means only.

An unknown slug, an unsupported key or a wrong type returns 400 with code: "invalid_provider" and the parameter. A provider that cannot run the model for your workspace returns 404 provider_not_available, naming the ones you can use. A provider takes tool calls or JSON schema only once it has passed our tests for them, so pinning one that has not returns 400 for those requests; model pages show which providers have passed.

The price is the model's list price unless its model page shows a provider's own price. Receipts do not show which provider served a request.