API REFERENCE
Responses and token usage
Read generated text, finish reasons, token counts, and request identifiers.
Response shape
A non-streaming Chat Completions response contains choices. The usual text answer is choices[0].message.content; tool calls can produce a null text value and structured tool_calls instead. Handle missing choices and errors before accessing the answer.
{
"id": "chatcmpl-example",
"object": "chat.completion",
"model": "<MODEL_ID>",
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "A trace connects the steps in one operation." },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 30,
"completion_tokens": 12,
"completion_tokens_details": { "reasoning_tokens": 8 },
"total_tokens": 42
}
}This is an illustrative shape, not measured usage. Typical finish reasons include stop, length, and tool_calls, depending on the model. length means generation reached a limit; do not present an incomplete answer as complete.
usage.prompt_tokens counts input tokens and usage.completion_tokens counts generated tokens. Some providers include cached input at usage.prompt_tokens_details.cached_tokens; absent cache reporting is not proof that caching is disabled. Cache tokens are a subset of prompt tokens, not additional input to add again.
usage.completion_tokens_details.reasoning_tokens is the provider-reported reasoning-token count, when available. These tokens are included in completion_tokens; do not add them again to output or total tokens. Prefer the nested field when both it and the compatible flat usage.reasoning_tokens field are present. Missing counts remain absent, not zero or an estimate derived from visible reasoning. reasoning.exclude: true hides reasoning output but does not remove generated reasoning from usage or billing.
With @openrouter/ai-sdk-provider 3.x, the provider result maps this nested count to usage.outputTokens.reasoning; usage.outputTokens.total remains total completion tokens. Some SDKs default missing reasoning usage to zero, so inspect the raw API usage object when distinguishing unreported usage from an actual reported zero.
Reasoning uses choices[0].message.reasoning and optional reasoning_details, separately from content. The legacy reasoning_content alias remains compatible. Display nonempty details before either plaintext alias to avoid showing the same text twice. Provider detail objects retain their original order, IDs, format, signatures, and encrypted data. Where only plaintext is available, Netra can wrap that actual text with format: "unknown"; it never invents a provider signature, encrypted payload, summary, or token count. Reasoning exclusion removes response reasoning fields after usage accounting. Do not infer usage from visible text length.
Record the HTTP X-Request-Id response header for support and Observe lookup. The provider's JSON response id is a separate identifier and may not be the Netra request ID. Keep the request ID, model, timestamp with timezone, status, and safe timing information in application logs; keep secrets and prompt bodies out by default.
Usage and credit settlement may become visible after the response completes. Use the settled usage record to reconcile spend. Usage may be estimated when exact token counts are unavailable; a missing response usage object does not mean the call was free.