What the API is
Tokener CA is one API you reach with one key over three protocols: OpenAI-compatible (Chat Completions), OpenAI Responses and Anthropic-compatible (Messages). OpenAI clients point at https://a.tokener.ca/v1; the Anthropic SDKs point at https://a.tokener.ca (no /v1 — the SDK appends it). To get a key, follow the Quickstart; the tool-by-tool guides are linked from each row below.
This page states what every endpoint accepts and returns. For step-by-step setup, use the Developer Onboarding, OpenAI Responses API and Anthropic SDK guides.
Endpoints
| Method and path | Protocol | What it does | Guide |
|---|---|---|---|
POST https://a.tokener.ca/v1/chat/completions | OpenAI-compatible (Chat Completions) | Create a chat completion | Developer Onboarding |
POST https://a.tokener.ca/v1/responses | OpenAI Responses | Create a response, sending the whole conversation each time | OpenAI Responses API |
POST https://a.tokener.ca/v1/messages | Anthropic-compatible (Messages) | Create a message | Anthropic SDK |
POST https://a.tokener.ca/v1/messages/count_tokens | Anthropic-compatible (Messages) | Count a request's input tokens (free; see availability below) | Anthropic SDK |
GET https://a.tokener.ca/v1/models | — | List the models you can call | Developer Onboarding |
POST https://a.tokener.ca/v1/messages/count_tokens returns { "input_tokens": <n> } for a Messages request. It is free — not charged and not recorded — but needs a valid key on an account with a positive balance; model must be a current model and messages non-empty. Token counting is available only on accounts that have turned on Also allow suppliers without that commitment under Account settings → Data handling; on other accounts this endpoint answers 404 not_found_error with the message "Token counting is not available on this API."
Authentication
Every request needs your Tokener API key, which begins with tok-.
- OpenAI-compatible (Chat Completions), OpenAI Responses and
GET /models: sendAuthorization: Bearer <your key>. - Anthropic-compatible (Messages): send
x-api-key: <your key>(the Anthropic SDK default) orAuthorization: Bearer <your key>. If both are present,x-api-keyis used.
A missing or invalid key is answered with 401. A revoked key is treated exactly like an invalid one — revoking takes effect immediately, so create a new key on the API keys page. A request from a deactivated account is answered with 403, before any billing.
Requests
Tokener validates only a few fields and passes everything else through to the model unchanged.
OpenAI-compatible (Chat Completions)
Requires model (a non-empty string) and a non-empty messages array.
curl https://a.tokener.ca/v1/chat/completions \ -H "Authorization: Bearer $TOKENER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5.3:flash", "messages": [{ "role": "user", "content": "Hello" }] }'OpenAI Responses
Requires model and a non-empty input (a string or an array). This endpoint is stateless: previous_response_id, conversation, store: true and background: true are rejected — send the whole conversation in input.
curl https://a.tokener.ca/v1/responses \ -H "Authorization: Bearer $TOKENER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5.3:flash", "input": "Hello" }'Anthropic-compatible (Messages)
Requires model, a non-empty messages array, and max_tokens (a positive integer).
curl https://a.tokener.ca/v1/messages \ -H "x-api-key: $TOKENER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "Content-Type: application/json" \ -d '{ "model": "glm-5.3:flash", "max_tokens": 128, "messages": [{ "role": "user", "content": "Hello" }] }'How do I send an image?
Image parts must be inline base64 data URLs — data:image/<type>;base64,<data> — on every protocol. Tokener does not fetch remote images: a part that points at an http:// or https:// URL is rejected with 400 invalid_request_error ("Image parts must be inline data URLs (base64); remote image URLs are not fetched.") before the request reaches a model, and nothing is charged. Download the image yourself and encode it — see Developer Onboarding.
- OpenAI-compatible (Chat Completions):
{ "type": "image_url", "image_url": { "url": "data:image/png;base64,…" } } - OpenAI Responses:
{ "type": "input_image", "image_url": "data:image/png;base64,…" } - Anthropic-compatible (Messages):
{ "type": "image", "source": { "type": "base64", "media_type": "image/png", "data": "…" } }— asourceof typeurlis rejected.
Which models accept images is shown per model on /models under its input modalities.
Streaming
Each protocol streams over server-sent events; turn it on with "stream": true.
- OpenAI-compatible (Chat Completions): each
data:line is a chunk whosechoices[0].deltacarries the next piece of text; the stream ends withdata: [DONE]. - OpenAI Responses: typed events, where
response.output_text.deltacarries text; the stream ends with aresponse.completedevent. See the OpenAI Responses API guide. - Anthropic-compatible (Messages): Anthropic SSE with paired
event:/data:lines —message_start, thencontent_block_deltaevents with the text, thenmessage_deltaandmessage_stop. See the Anthropic SDK guide.
Once a streamed response has started (HTTP 200), a later failure arrives as an event inside the stream and the connection closes, rather than as a new status code.
Usage and billing fields
Every non-streamed response carries a usage object; on a stream the final counts arrive in the last event (the final chunk, the response.completed event, or the closing message_delta). See How the numbers are counted and billed below, and Pricing for the live price list.
| Protocol | Token-count fields on usage |
|---|---|
| OpenAI-compatible (Chat Completions) | prompt_tokens, completion_tokens, total_tokens, prompt_tokens_details.cached_tokens |
| OpenAI Responses | input_tokens, output_tokens, total_tokens, input_tokens_details.cached_tokens |
| Anthropic-compatible (Messages) | input_tokens, output_tokens, cache_read_input_tokens, cache_creation_input_tokens |
How the numbers are counted and billed
-
OpenAI-compatible (Chat Completions) and OpenAI Responses: the input count (
prompt_tokens/input_tokens) is the total input of the request. The cached count (prompt_tokens_details.cached_tokens/input_tokens_details.cached_tokens) is a part of that total — it is already included in it, so never add it on top. -
Anthropic-compatible (Messages): the native fields can report cached input either inside
input_tokensor next to it (cache_read_input_tokens,cache_creation_input_tokens), depending on how the request was served, and the response does not say which. Tokener therefore bills this protocol from the request's input total, which it determines on the server; when that total cannot be confirmed it bills the lower reading. Do not reconstruct a bill from these three fields — the Usage page is authoritative. -
What you are charged. The charge for a request is:
charge = (input total − cached input) × input rate + cached input × cache-read rate + output × output rateA model that has no cache-read rate bills cached input at its input rate. Rates are per 1,000,000 tokens and are listed on /models. Cache creation is billed as ordinary input — there is no separate write surcharge.
-
Cache hits are never guaranteed. Reusing a conversation does not imply a cache hit; whether any input was cached is decided per request and is reflected in the usage of that response.
-
Streaming. The final usage arrives at the end of the stream, per protocol, as described under Streaming above. A stream you stop early may end without a final usage.
-
Counting before you send. On the Anthropic-compatible (Messages) protocol,
POST https://a.tokener.ca/v1/messages/count_tokensreturns a request's input total before you send it, and is free — on accounts that allow all model suppliers in their Data handling settings; see Anthropic SDK. -
Where to check. Every request is listed on the Usage page with the columns In, Out, Total, Cost (US$), Status, Protocol, Error and Key. When part of the input was cached, the cached count is shown in parentheses beside the In value (for example "1,200 (800 cached)"); there is no separate cached column.
What is a limited-time price?
Some models may be on a limited-time price: a lower price for a set period. While it runs, the model's card on /models, its own page, the home page and Pricing show the regular price struck through with the limited-time price under it, how much is off (for example "26% off", or "Limited-time price"), and when it ends, in Toronto time (ET). The Playground shows the same next to the model's rates.
- A request is billed at the price in effect when it starts, even if it finishes after the end.
- When the end passes, the regular price applies again by itself.
- If your account allows all model suppliers in its Data handling settings, that discount applies on top of the limited-time price.
Errors
Errors on the OpenAI-shaped endpoints (OpenAI-compatible (Chat Completions), OpenAI Responses, GET /models) use the body { "error": { "message", "type", "code", "param" } }.
| Status | type | code | When | What to do |
|---|---|---|---|---|
| 400 | invalid_request_error | invalid_request_error | A required field is missing or malformed | Fix the request body |
| 400 | invalid_request_error | model_not_found | The model is unknown or not available | Pick a model from /models |
| 401 | invalid_request_error | invalid_api_key | The key is missing, invalid or revoked | Check the Authorization header or create a new key |
| 402 | insufficient_quota | insufficient_quota | Your balance is used up | Add funds — see Pricing |
| 402 | insufficient_quota | plan_limit_reached | Your Agent plan reached its 5-hour or weekly limit and "continue on my balance" is off | Wait for Retry-After seconds, turn the setting on, or add funds |
| 402 | insufficient_quota | overflow_cap_reached | Your Agent plan is at a limit and your own limit on balance use beyond the plan for this billing period is reached | Wait for Retry-After seconds, or raise the limit on the Plan page |
| 403 | invalid_request_error | account_deactivated | The account is deactivated | Contact support |
| 413 | invalid_request_error | request_too_large | The request body is too large for this model | Send less context or smaller attachments |
| 429 | rate_limit_error | rate_limit_exceeded | The request was rate-limited | Slow down and try again |
| 502 | api_error | upstream_error | A temporary upstream failure | Try again |
| 503 | api_error | model_limited_by_data_handling | The model is temporarily available only from suppliers your Data handling setting does not allow, and the request failed (details) | Turn on the setting or pick another model |
| 500 | api_error | internal_error | An unexpected server error | Try again, then contact support |
Errors on the Anthropic-compatible (Messages) endpoint use the Anthropic body { "type": "error", "error": { "type", "message" } }.
| Status | type | When | What to do |
|---|---|---|---|
| 400 | invalid_request_error | The request body is invalid | Fix the request body |
| 401 | authentication_error | The key is missing, invalid or revoked | Check x-api-key or create a new key |
| 402 | billing_error | Your balance is used up, or your Agent plan reached a limit, or your limit on balance use beyond the plan is reached (then Retry-After is set; the message tells them apart) | Add funds — see Pricing, wait for Retry-After seconds, or raise the limit on the Plan page |
| 403 | permission_error | The account is deactivated | Contact support |
| 404 | not_found_error | The model is unknown or not available (or, on count_tokens, token counting is not available for the account) | Pick a model from /models |
| 413 | request_too_large | The request body is too large for this model | Send less context or smaller attachments |
| 429 | rate_limit_error | The request was rate-limited | Slow down and try again |
| 502 | api_error | A temporary upstream failure | Try again |
| 503 | api_error | The model is temporarily available only from suppliers your Data handling setting does not allow, and the request failed (the message says so) | Turn on the setting or pick another model |
| 500 | api_error | An unexpected server error | Try again, then contact support |
If the model itself rejects a request — for example a parameter it does not accept — Tokener returns a 400 in the shape above asking you to check your parameters.
What if a model is marked Temporarily unavailable?
The Models pages mark a model Temporarily unavailable when our automatic checks cannot reach it. The API still accepts requests for it, and a request that fails is not billed. Pick another model, or retry later — the mark goes away by itself as soon as a check succeeds.
Why did my request fail with model_limited_by_data_handling?
By default your requests go only to model suppliers that commit to not storing request
content and not using it for training. Sometimes a model is temporarily available only from
suppliers without that commitment. If a request for that model then fails, the answer is a
503 with the code model_limited_by_data_handling (on the Anthropic-compatible (Messages)
endpoint: a 503 api_error with the same message) instead of the usual failure, so you
know why. The request was not billed. To use the model now, turn on "Also allow suppliers
without that commitment" in Settings → Data handling, or
choose another model. Accounts that already allow those suppliers never get this error.
Related
- Developer Onboarding, OpenAI Responses API and Anthropic SDK — how to set up each protocol.
- Models — the models you can call, with prices and capabilities.
- Pricing — how per-token billing works.
- FAQ — common questions about keys, billing and data.
- Playground guide — try a model and copy the equivalent code.
