Usage and cost

Read the usage object on each response: token counts, billable and cached tokens, the shape of the cost object, and how a stream reports usage.

Every chat response reports what the call consumed in a usage object: its token counts and a cost object. This page documents the shape of both. Cost amounts and rates are specific to your account and shown in your Cruxy Console, so the examples here use placeholders where those numbers go. Read the real values from your own responses.

# usage, with its cost object, is near the end of the response body.
curl https://api.cruxy.ai/api/v1/chat \
  -H "Authorization: Bearer $CRUXY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vaani",
    "messages": [
      { "role": "user", "content": "Name three monsoon fruits." }
    ]
  }'

The usage object

A non-streaming POST /api/v1/chat response carries usage next to message. input_tokens, output_tokens, billable_input_tokens, and cost are always present.

FieldMeaning
input_tokensThe call's input tokens.
output_tokensThe tokens the model generated.
billable_input_tokensThe input tokens the call is billed for.
cache_read_tokensInput tokens read from the prompt cache.
cache_write_tokensInput tokens written to the prompt cache.
prompt_tokens_detailsThe same cache split in OpenAI's shape, cached_tokens and cache_write_tokens. Present only when the prompt cache was used.
costWhat the call cost, as an object; see The cost object.

The token fields have different names on different endpoints. Each set belongs to a wire contract that has already shipped, so read the one for the endpoint and mode you called:

Endpoint and modeToken fieldsCost
POST /api/v1/chat, stream: falseinput_tokens, output_tokens, billable_input_tokens, cache_read_tokens, cache_write_tokensusage.cost
POST /api/v1/chat, stream: trueprompt_tokens, completion_tokens, total_tokens, plus the three Cruxy counts when they are not zerousage.cost, on the usage frame
POST /api/v2/chat, either modeinput_tokens, output_tokens, billable_input_tokens, cache_read_tokens, cache_write_tokensusage.cost
POST /api/v1/embeddings and POST /api/v1/rerankprompt_tokens, total_tokenscruxy.cost
POST /v1/chat/completionsprompt_tokens, completion_tokens, total_tokens, and prompt_tokens_details.cached_tokens when the cache was usedNot in the response
POST /api/v1/moderationsNot in the responseNot in the response

The cost object

cost is an object, not a number. Read cost.amount when you want one figure.

{
  "tier": "vaani",
  "amount": "<amount>",
  "currency": "<currency>",
  "input_unit": "<input rate>",
  "output_unit": "<output rate>",
  "cache_read_unit": "<cache read rate>"
}

Each <…> is a placeholder. In a real response, currency is a string and the other placeholders are numbers.

FieldMeaning
tierThe tier that served the call.
amountThe modeled cost of the call, in currency.
currencyThe currency of amount.
input_unitThe input rate amount was computed from, per million tokens.
output_unitThe output rate, per million tokens.
cache_read_unitThe rate for input read from the prompt cache, per million tokens: the tier's own cache-read rate where it has one, otherwise input_unit times the cache discount.

Amounts and rates are specific to your account, and your Cruxy Console shows them. Take cost.amount from each response rather than computing it from token counts and a rate you copied, so your numbers match what the gateway records.

Billable and cached tokens

More goes into input_tokens than the messages you send. Each of these is billed as input:

  • The tier's own prompt. The gateway adds a per-tier system prompt and the tier's chat-template scaffolding.
  • Standing rules, when they are injected into the turn; see Standing rules.
  • Recalled memory, when recall runs. Sending memory: {"recall": false} lowers input by the size of that block; see Memory.
  • Attached files, on every request that sends them, including later turns that replay a message with file_ids in its history.
  • Tools. The tools array you send is real input; see Define tools.

billable_input_tokens is the input the call is billed for, and cache_read_tokens and cache_write_tokens count prompt-cache activity. Input read from the cache is priced at cost.cache_read_unit. The API does not document how these counts relate to input_tokens, so read each one as reported rather than deriving one from another.

Thinking is output. A reasoning tier writes its thinking inside the same max_tokens budget as the answer, POST /api/v2/chat reports that output_tokens includes the reasoning, and no response carries a separate reasoning-token count. See Reasoning effort.

To size a request before you send it, POST /api/v1/tokens/count returns the input_tokens a chat request would bill for the same tier, messages, and tools. It calls no model and is not billed. The count is exact for single-turn and user-only prompts on every tier, and never an undercount: where it can differ from the real call, it errs high. It takes a tier, not "auto", and refuses file_ids.

How a stream reports usage

Usage arrives once, at the end of a successful stream:

  • POST /api/v1/chat sends exactly one usage frame: the frame whose choices is an empty array, after the finish frame and before data: [DONE]. It always carries cost. billable_input_tokens, cache_read_tokens, and cache_write_tokens are left out when they are zero, and prompt_tokens_details appears only when the cache was used, so a missing field means zero. See Streaming.
  • POST /api/v2/chat carries usage on its terminal finish frame, in the same shape as a non-streaming v2 response. Its error frame can carry usage too.
  • POST /v1/chat/completions sends a usage frame only when the request sets stream_options: {"include_usage": true}, and that usage has no cost.

A stream that fails partway sends no usage frame. The tokens it delivered were real, though, and are billed as a partial usage row.

What is billed

Not billed:

  • A non-streaming chat that runs past its tier's deadline: 504 upstream_timeout.
  • A model failure on chat: 502 upstream_error, and the 503 codes upstream_overloaded, model_unavailable, all_models_unavailable, server_shutting_down, and limits_unavailable.
  • A request the input moderation gate refuses: 400 moderation_rejected.
  • A request refused for its Cruxy-Version, for an attached file, or for the memory, rules, or files scope its key lacks: these are answered before anything is billed.
  • A replay of a stored success under the same Idempotency-Key.
  • POST /api/v1/tokens/count, and uploads to POST /api/v1/files.

Billed:

  • 422 structured_output_unsatisfied. A retry with the same Idempotency-Key and body is not billed a second time.
  • A stream that ended early, for the tokens it delivered.
  • Every case in an eval run, as a chat completion.

When a streamed request is retried under the same Idempotency-Key, it is billed once if both attempts complete. An attempt that did not complete is billed for the tokens it delivered, and the retry is billed as well; see Errors and retries.

Track spend

  • Spend caps and credit. GET /api/v1/limits reports the caps that bind your key: key_spend_cap and workspace_spend_cap, each with cap, spent, remaining, resets_at, and unit, and a headless key's credits. See Rate limits and budgets.
  • Per-request tokens. An organization owner or admin can read any call's token counts by its request_id; see Look up a request.
  • Amounts. Your Cruxy Console shows what your usage costs.

Next steps

Was this page helpful?