Reference
Usage & billing
Reconcile token usage, request cost, balances, and asynchronous settlement.
On this page
This page is for developers and finance operators reconciling API responses with key balances and request logs.
Usage and cost authority#
Response bodies are passed through. Token fields depend on the protocol and upstream API. When an OpenAI-compatible response includes a finite non-negative usage.cost, that upstream-reported value is the charge authority. Otherwise the billing worker uses its local price table. Reasoning and thinking tokens are charged as output tokens.
For OpenAI-compatible prompt caching, usage.cost already reflects any upstream cache discount. Clients do not need to calculate a separate discount from cached-token fields.
{"usage":{"prompt_tokens":120,"completion_tokens":30,"total_tokens":150,"cost":0.00042}}If no price can be found, the request can be logged as unpriced for later reconciliation. Binary responses without usage, such as speech audio, can use a request-text estimate that is marked as estimated in the cost breakdown.
Balance and allocation#
Read a key's balance projection with authenticated GET /v1/balance:
curl https://api.clssai.com/v1/balance \
-H "Authorization: Bearer $CLSSAI_API_KEY"{
"object": "balance",
"key": "sk-...abc123",
"identity": "account",
"remaining_usd": 2.25,
"limit_usd": 2.5,
"recharge_usd": 2,
"credit_usd": 1,
"allocated_usd": 0.5,
"consumption_usd": 0.25,
"grace_usd": 0.1,
"expires_at": null,
"expired": false,
"disabled": false,
"tier": "free",
"tier_until": null,
"settlement": "asynchronous",
"note": "consumption_usd settles asynchronously and can lag recent requests by minutes; shared child Keys report the parent balance."
}identity is one of account, allocated_child, or shared_child. An allocated child has its own funded balance. A shared child returns its parent's balance but never exposes the parent key, and its usage is billed to that parent.
The key limit is recharge_usd + credit_usd - allocated_usd, and remaining_usd = max(limit_usd - consumption_usd, 0). Allocation is the amount assigned to independently funded child keys. expires_at is null for a key with no expiry, otherwise a Unix timestamp in seconds. Expired or disabled keys still receive a 200 response from this balance endpoint, with expired or disabled set to true; callers must inspect those fields. tier is the account's membership (free, plus, pro, or business) and tier_until the end of its current period in Unix seconds, or null on free.
Each key has a small grace_usd amount that can allow a request at the admission boundary. grace_usd is a small request-admission allowance, not spendable balance; do not include it in remaining_usd.
Manage balances at Credits (sign-in required).
Settlement is asynchronous#
Requests enter a billing queue without waiting for settlement. consumption_usd, remaining_usd, and aggregate consumption can therefore lag request completion by several minutes. The response reports settlement: "asynchronous"; do not expect an inference response and the balance projection to change atomically.
Account endpoints#
Four authenticated GET routes report the calling key's own money and usage. They answer from local account data and request logs, never from another account, and never from a third-party console. All four send Cache-Control: no-store and Access-Control-Expose-Headers: Retry-After.
| Endpoint | Answers |
|---|---|
GET /v1/balance | Balance projection and key state (see above). |
GET /v1/key | The calling key's record: label, limit, usage windows, tier, expiry. |
GET /v1/credits | Lifetime credits purchased and used for the calling key. |
GET /v1/generation?id=<id> | Cost, tokens, and latency for one of the calling key's own generations. |
Key record#
curl https://api.clssai.com/v1/key \
-H "Authorization: Bearer $CLSSAI_API_KEY"{
"data": {
"label": "example-production-key",
"limit": 5,
"limit_remaining": 4.945202,
"limit_reset": null,
"usage": 0.054798,
"usage_daily": 0.05479844,
"usage_weekly": 0.05479844,
"usage_monthly": 0.05479844,
"is_free_tier": true,
"is_management_key": false,
"is_provisioning_key": false,
"expires_at": "2026-10-05T02:31:08.000Z",
"allowed_data_regions": ["global"],
"free_model_daily_requests": {
"used": 84,
"limit": 0,
"remaining": 0
},
"rate_limit": {
"requests": 30,
"interval": "10s",
"note": "Per-key request rate; requests over it are queued or rejected with 429."
}
}
}| Field | Meaning |
|---|---|
label | Display name chosen when the key was created. |
limit | Spending limit in USD for this key, or a sentinel when unlimited. |
limit_remaining | Remaining USD under limit. |
limit_reset | Reset cadence for limit, or null. |
usage | Lifetime settled usage in USD for this key. |
usage_daily | Usage since 00:00 UTC today. |
usage_weekly | Usage since Monday 00:00 UTC. |
usage_monthly | Usage since the 1st of the month, 00:00 UTC. |
is_free_tier | Whether the key is on the free tier. |
is_management_key | Whether the key is a management key. |
is_provisioning_key | Whether the key is a provisioning key. |
expires_at | Expiry as an ISO-8601 timestamp, or null when the key does not expire. |
allowed_data_regions | Data regions this key may use. |
free_model_daily_requests | Free-model pool counters: used, limit, remaining. |
rate_limit | Request budget for these account queries (see rate limits below). |
Daily, weekly, and monthly windows are UTC. Window counters settle asynchronously and can lag recent requests by a few minutes.
Credits summary#
curl https://api.clssai.com/v1/credits \
-H "Authorization: Bearer $CLSSAI_API_KEY"{"data":{"total_credits":5,"total_usage":0.054798}}| Field | Meaning |
|---|---|
total_credits | Current wallet total (top-ups + grants − allocations), in USD. |
total_usage | Lifetime spend, in USD. |
Generation lookup#
GET /v1/generation?id=<id> returns one generation that belongs to the calling key. Accepted id shapes include gen-…, resp_…, and msg_…. IDs starting with gen- are located from their embedded timestamp; every other shape is searched only in the last 6 hours. Logs become queryable about one minute after the request finishes. Another account's id returns 404 not_found, so the endpoint cannot be used to enumerate other users' traffic.
curl "https://api.clssai.com/v1/generation?id=gen-1790569230-BQqOLNDTIJLngMEDcMIR" \
-H "Authorization: Bearer $CLSSAI_API_KEY"{
"data": {
"id": "gen-1790569230-BQqOLNDTIJLngMEDcMIR",
"upstream_id": null,
"total_cost": 8.85e-06,
"usage": 8.85e-06,
"cache_discount": null,
"created_at": "2026-09-28T04:20:31.851Z",
"model": "openai/gpt-5.4-nano",
"streamed": false,
"cancelled": false,
"latency": 1147,
"moderation_latency": null,
"generation_time": 1370,
"finish_reason": "stop",
"native_finish_reason": "stop",
"service_tier": null,
"tokens_prompt": 13,
"native_tokens_prompt": 13,
"tokens_completion": 5,
"native_tokens_completion": 5,
"native_tokens_cached": 0,
"native_tokens_reasoning": 0,
"api_type": "completions",
"data_region": "global"
}
}| Field | Meaning |
|---|---|
id | Generation id as queried. |
upstream_id | Provider-side id when one was recorded, otherwise null. |
total_cost | Settled charge for this generation in USD. |
usage | Same figure as total_cost. |
cache_discount | Prompt-cache discount applied to the charge, or null. |
created_at | Completion time in UTC. |
model | Resolved author/model ID. |
streamed | Whether the response was streamed. |
cancelled | Whether the request was cancelled. |
latency | End-to-end latency in milliseconds. |
moderation_latency | Moderation time in milliseconds, or null. |
generation_time | Generation time in milliseconds. |
finish_reason | Normalized finish reason, for example stop or length. |
native_finish_reason | Finish reason as reported by the model. |
service_tier | Service tier used, or null. |
tokens_prompt | Prompt tokens billed. |
native_tokens_prompt | Prompt tokens as reported by the model. |
tokens_completion | Completion tokens billed. |
native_tokens_completion | Completion tokens as reported by the model. |
native_tokens_cached | Cached prompt tokens reported by the model. |
native_tokens_reasoning | Reasoning tokens reported by the model. |
api_type | Request surface that produced the generation, for example completions. |
data_region | Data region that served the request. |
Missing id, a foreign id, or a still-unwritten log returns 404 with code not_found. A missing id query parameter returns 400 with code missing_id.
How the numbers line up#
/v1/balance, /v1/key, and /v1/credits share one ledger for the calling key:
/v1/balance | /v1/key | /v1/credits |
|---|---|---|
limit_usd | limit | total_credits |
consumption_usd | usage | total_usage |
remaining_usd | limit_remaining | total_credits - total_usage |
expires_at (Unix seconds) | expires_at (ISO-8601) | — |
Use /v1/balance for the admission projection (remaining_usd, grace_usd, expired, disabled). Use /v1/key for label, tier, and window counters. Use /v1/credits when a client only needs two lifetime totals. Use /v1/generation to reconcile a single request's charge. All four lag recent inference by the same asynchronous settlement delay.
Rate limits and errors#
These account queries have their own budgets, separate from inference traffic:
| Endpoint | Budget |
|---|---|
GET /v1/key, GET /v1/credits | 30 requests per 10 seconds, shared per key. |
GET /v1/generation | 5 requests per 10 seconds per key, and 1 in-flight lookup per key. |
Exceeding a budget returns 429 with an integer Retry-After header in seconds and this body:
{"error":{"message":"Too many account requests. Retry after 1 seconds.","type":"invalid_request_error","param":null,"code":"rate_limited"}}Retry-After is the number of seconds until the next slot. Concurrent generation lookups above one return the same 429 with Retry-After: 1. Account-query 429 responses are distinct from the free daily pool 429; see Errors & rate limits.
Reconcile request logs#
The key appears in the management path, so construct this URL only in trusted server tooling and never log it. The range, page, and page_size query parameters select the time window, result page, and requested rows per page.
curl "https://api.clssai.com/key/$CLSSAI_API_KEY/logs.json?range=24h&page=1&page_size=30" \
-H "Content-Type: application/json"The top-level JSON object contains:
| Field | Meaning |
|---|---|
error | Error value reported by the endpoint. |
range | Effective time-window selection. |
source | Log source reported for the result set. |
page | Current result page. |
page_size | Effective number of rows per page. |
total | Total number of matching rows. |
total_pages | Total number of result pages. |
window_start | Start of the selected time window. |
window_end | End of the selected time window. |
items | Array of request-log rows. |
Each items[] row contains:
| Field | Meaning |
|---|---|
time | Request time. |
provider | Provider recorded for the request. |
status | Recorded status label. |
status_code | Recorded HTTP status code. |
cached | Whether this response was returned from an upstream gateway cache. |
model | Model recorded for the request. |
tokens_in | Recorded input-token count. |
tokens_out | Recorded output-token count. |
cost | Recorded request cost. |
count | Count value reported for the row. |
duration_ms | Recorded request duration in milliseconds. |
upstream_id | Upstream identifier recorded for the request. |
source | Source recorded for the request. |
For native Anthropic requests, tokens_in and tokens_out omit the cache_creation_input_tokens and cache_read_input_tokens counters, so those two logged token values alone cannot be used to reproduce cost.
Free models and the daily pool#
A complete model ID ending in :free has zero local token prices, unless an upstream-reported cost overrides them. Free users also share a separate global daily pool. When that pool is exhausted, the gateway returns 429. These are distinct limits.
Common mistakes#
- Do not assume settlement is real-time.
- Do not subtract only consumption; account for recharge, credit, and allocated amounts.
- Do not assume a 200 balance response means the key is active; inspect
expiredanddisabled. - Do not add
grace_usdto available balance. - Do not publish or log a key-bearing management URL.
- Preserve the complete
author/model:freeorauthor/model:batchID. - Include
/v1in OpenAI SDK base URLs, omit it from the Anthropic SDK base URL, and call from a server. - Check empty streaming
choicesarrays and retaincf-rayfor inference tracing. - Do not expect
/v1/keywindow counters to update instantly; they share the asynchronous settlement delay. - Do not treat
/v1/generationas a public log search: only the calling key's own ids resolve, and anything outside the recent window returns 404not_found. - Honor
Retry-Afteron account-endpoint 429rate_limitedresponses instead of retrying immediately.
Find answers to common questions or diagnose a failed request.
Frequently asked questions →Troubleshoot errors →