> ## Documentation Index
> Fetch the complete documentation index at: https://developers.meshapi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Usage Object

> The usage block on Chat Completions, Responses and Messages: the fixed keys, provider keys, which cache counts each provider reports, and how to read a gateway cache hit.

Every successful completion returns a `usage` object that counts the tokens the request consumed. On each of `POST /v1/chat/completions`, `POST /v1/responses` and `POST /v1/messages`, the usage carries a **fixed set of keys** in that endpoint's own format, whichever provider served the request. The **values** in it, the cache counts especially, still depend on what that provider reports.

Keys the serving provider adds on its own are returned alongside the fixed ones — see [Provider keys](#provider-keys).

<Note>
  The per-provider behaviour on this page was observed on 8 October 2026. It follows the **serving provider**, so it can change when a provider changes its API or when MeshAPI routes a model differently. To see which provider served a request, read `event.provider` from [`GET /v1/usage/requests/{request_id}`](/api/usage/get-request).
</Note>

## Chat Completions usage

Every chat completion returns these keys:

```json theme={null}
{
  "prompt_tokens": 4701,
  "completion_tokens": 29,
  "total_tokens": 4730,
  "prompt_tokens_details": {
    "cached_tokens": 4686,
    "cache_write_tokens": 0,
    "cache_write_1h_tokens": 0,
    "audio_tokens": 0
  },
  "completion_tokens_details": {
    "reasoning_tokens": 0,
    "audio_tokens": 0,
    "accepted_prediction_tokens": 0,
    "rejected_prediction_tokens": 0
  },
  "byok_used": false,
  "fallback_triggered": false
}
```

The same keys appear on streamed and non-streamed responses. A count that is unused, or that the provider doesn't report, is `0`.

| Field | Meaning |
| - | - |
| `prompt_tokens` | All input tokens, **including** tokens read from or written to the prompt cache |
| `completion_tokens` | Output tokens |
| `total_tokens` | `prompt_tokens + completion_tokens` |
| `prompt_tokens_details.cached_tokens` | Input tokens read from the provider's prompt cache |
| `prompt_tokens_details.cache_write_tokens` | Input tokens written to the prompt cache, all TTLs combined |
| `prompt_tokens_details.cache_write_1h_tokens` | The part of `cache_write_tokens` written with a 1-hour TTL |
| `prompt_tokens_details.audio_tokens` | Audio input tokens |
| `completion_tokens_details.reasoning_tokens` | Tokens the model spent reasoning, where the provider reports them |
| `completion_tokens_details.audio_tokens` | Audio output tokens |
| `completion_tokens_details.accepted_prediction_tokens` / `rejected_prediction_tokens` | Predicted-output tokens that were accepted / rejected |
| `byok_used` | `true` if the request was served with your own provider key — see [BYOK](/docs/capabilities/byok) |
| `fallback_triggered` | `true` if MeshAPI fell back to another provider or model to serve the request — see [Retry and fallback](/docs/platform/retry-and-fallback) |

<Warning>
  **Deprecated:** some responses also carry a top-level `cache_creation_input_tokens`. It duplicates `prompt_tokens_details.cache_write_tokens` and appears only on a cache write served by Bedrock, for example on Anthropic Claude or Amazon Nova models. Read `cache_write_tokens` instead.
</Warning>

### Provider keys

Besides the fixed keys, `usage` carries any other key the serving provider reported, unchanged. For example:

```json theme={null}
{
  "prompt_tokens": 1000, "completion_tokens": 10, "total_tokens": 1010,
  "prompt_tokens_details": { "cached_tokens": 640, "cache_write_tokens": 0, "cache_write_1h_tokens": 0, "audio_tokens": 0 },
  "completion_tokens_details": { "reasoning_tokens": 0, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0 },
  "byok_used": false, "fallback_triggered": false,
  "prompt_cache_hit_tokens": 640,
  "prompt_cache_miss_tokens": 360
}
```

Here `prompt_cache_hit_tokens` and `prompt_cache_miss_tokens` come from DeepSeek; the same count is also in `cached_tokens`. Other examples are OpenRouter's `is_byok` and xAI's `num_sources_used`. Provider keys can also appear inside `prompt_tokens_details` and `completion_tokens_details`.

* **Provider keys depend on the route.** They differ by provider and can change or disappear when a provider changes its API or MeshAPI routes a model differently. Build on the fixed keys.
* **A fixed key always holds MeshAPI's value.** If a provider sends a key with the same name, MeshAPI's value replaces it. OpenRouter's `is_byok` describes OpenRouter's own account. Read `byok_used` for whether your provider key served the request.
* **Provider cost figures are never returned.** Read your charge from the Usage API instead — see the note under [Summary](#summary).

The same rule applies on [Responses](#responses-api) and [Messages](#messages-api).

### What a `0` means

The keys are always present, but `0` can mean either "nothing happened" or "the provider doesn't report this":

* A route that doesn't report cache writes returns `cache_write_tokens: 0` even when the provider cached the prompt.
* A route that doesn't report the 1-hour split returns `cache_write_1h_tokens: 0` even after a 1-hour write.

The next section shows which routes report what.

## Cache reporting by serving provider

Which cache counts are filled in on `POST /v1/chat/completions`, by the provider that served the request:

| Serving provider | Models | Reports cache writes | Reports cache reads | Reports 1h writes separately |
| - | - | - | - | - |
| Bedrock (Anthropic) | `anthropic/claude-sonnet-4.6`, `anthropic/claude-haiku-4.5` | Yes | Yes | Yes |
| Bedrock (Amazon Nova) | `amazon/nova-pro-v1` | Yes | Yes | No |
| Bedrock (other models) | `moonshotai/kimi-k2.5`, `meta-llama/llama-4-scout` | No | No | No |
| OpenAI | `openai/gpt-5.6-terra` | Yes | Yes | n/a (no 1h TTL) |
| OpenAI | `openai/gpt-4o-mini`, `openai/gpt-5.4-mini` | No | Yes | n/a (no 1h TTL) |
| Google (Vertex) | `google/gemini-2.5-flash` | No | Yes | No |
| DeepInfra | `deepseek/deepseek-v4-flash` | No | Yes | No |
| DeepInfra | `google/gemini-3.1-pro` | No | No | No |
| xAI | `x-ai/grok-4.3` | No | Yes | No |
| Qwen | `qwen/qwen3-max` | No | Yes | No |
| Mistral | `mistralai/mistral-large-2512` | No | Yes | No |
| OpenRouter | `cohere/command-a` | No | No | No |

* **"No"** means the count is always returned as `0` on that route. The provider may still cache; it just isn't reported.
* **1-hour writes on Amazon Nova** are counted in `cache_write_tokens`, but `cache_write_1h_tokens` stays `0`.
* **Cache reads are best-effort** on providers that cache automatically (OpenAI, Google, DeepInfra, xAI, Qwen, Mistral). An identical repeat can still return `cached_tokens: 0`, and OpenAI can report a fresh write instead.

Which routes honour a `cache_control` marker in the first place is covered in [Caching](/docs/capabilities/caching#where-markers-are-honoured).

### Examples

These are real usage blocks, reformatted only.

<AccordionGroup>
  <Accordion title="Cache write — anthropic/claude-sonnet-4.6 on Bedrock, 1-hour TTL">
    ```json theme={null}
    {
      "prompt_tokens": 4701, "completion_tokens": 29, "total_tokens": 4730,
      "prompt_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 4686, "cache_write_1h_tokens": 4686, "audio_tokens": 0 },
      "completion_tokens_details": { "reasoning_tokens": 0, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0 },
      "byok_used": false, "fallback_triggered": false,
      "cache_creation_input_tokens": 4686
    }
    ```
  </Accordion>

  <Accordion title="Cache read — openai/gpt-5.6-terra">
    ```json theme={null}
    {
      "prompt_tokens": 4305, "completion_tokens": 24, "total_tokens": 4329,
      "prompt_tokens_details": { "cached_tokens": 4302, "cache_write_tokens": 0, "cache_write_1h_tokens": 0, "audio_tokens": 0 },
      "completion_tokens_details": { "reasoning_tokens": 0, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0 },
      "byok_used": false, "fallback_triggered": false
    }
    ```
  </Accordion>

  <Accordion title="Cache read with reasoning — x-ai/grok-4.3">
    ```json theme={null}
    {
      "prompt_tokens": 4493, "completion_tokens": 21, "total_tokens": 4514,
      "prompt_tokens_details": { "cached_tokens": 4480, "cache_write_tokens": 0, "cache_write_1h_tokens": 0, "audio_tokens": 0 },
      "completion_tokens_details": { "reasoning_tokens": 161, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0 },
      "byok_used": false, "fallback_triggered": false
    }
    ```
  </Accordion>
</AccordionGroup>

## Splitting input tokens

`prompt_tokens` includes cached and cache-written tokens:

```text theme={null}
fresh input tokens   = prompt_tokens - cached_tokens - cache_write_tokens
1-hour cache write   = cache_write_1h_tokens
other cache write    = cache_write_tokens - cache_write_1h_tokens
```

In the 1-hour write example above: 4701 − 0 − 4686 = 15 fresh tokens, and 4,686 tokens written with a 1-hour TTL. On Anthropic models, "other cache write" is the 5-minute TTL. What each kind of token costs is in [What it costs](/docs/capabilities/caching#what-it-costs).

## Streaming

On a streamed chat completion, the usage object arrives on the **final chunk**. You don't need `stream_options.include_usage`: MeshAPI requests usage from the provider on every stream. The keys are the same as on a non-streamed response.

On a Responses stream, usage arrives on the closing `response.completed` or `response.incomplete` event, under `response.usage`. On a Messages stream, it arrives on `message_delta`.

If the upstream fails partway through a stream, the response can end without a usage chunk.

## Gateway cache hits

When the MeshAPI [response cache](/docs/capabilities/caching#gateway-response-cache) answers a request:

* the response carries the header `X-Cache: HIT`
* the request is **not billed** — its `event.cost_usd` from [`GET /v1/usage/requests/{request_id}`](/api/usage/get-request) is `null`

The usage object on a hit is **not** a count of new work:

| Endpoint | Usage on a gateway hit |
| - | - |
| `/v1/chat/completions` | `prompt_tokens`, `completion_tokens` and `total_tokens` from the original response. All cache counts are `0`, and `cache_creation_input_tokens` is omitted. |
| `/v1/responses` | `input_tokens`, `output_tokens` and `total_tokens` from the original response. All cache counts are `0`. |
| `/v1/messages` | `input_tokens` holds the original request's **entire** input, including the cached part. The cache counts are `0`. |

Check `X-Cache` before using usage for cost tracking. To always reach the provider, send `X-Mesh-Cache: no-store`.

A Chat Completions hit on `anthropic/claude-haiku-4.5`, where the original response reported `cache_write_tokens: 4687`:

```json theme={null}
{
  "prompt_tokens": 4702, "completion_tokens": 26, "total_tokens": 4728,
  "prompt_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 0, "cache_write_1h_tokens": 0, "audio_tokens": 0 },
  "completion_tokens_details": { "reasoning_tokens": 0, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0 },
  "byok_used": false, "fallback_triggered": false
}
```

## Responses API

Every [`POST /v1/responses`](/docs/capabilities/responses-api) response returns these keys, in the OpenAI Responses format:

```json theme={null}
{
  "input_tokens": 4305,
  "input_tokens_details": {
    "cached_tokens": 0,
    "cache_write_tokens": 4302,
    "cache_write_1h_tokens": 0,
    "audio_tokens": 0
  },
  "output_tokens": 25,
  "output_tokens_details": {
    "reasoning_tokens": 0
  },
  "total_tokens": 4330,
  "byok_used": false,
  "fallback_triggered": false
}
```

The fields mean the same as their Chat Completions counterparts:

| Field | Same as on Chat Completions |
| - | - |
| `input_tokens` | `prompt_tokens`. It **includes** cache reads and writes. |
| `input_tokens_details.*` | `prompt_tokens_details.*` |
| `output_tokens` | `completion_tokens` |
| `output_tokens_details.reasoning_tokens` | `completion_tokens_details.reasoning_tokens` |
| `total_tokens` | `total_tokens`, as the serving provider reported it |
| `byok_used`, `fallback_triggered` | The same |

Provider keys are returned alongside, as on [Chat Completions](#provider-keys). What each serving provider reports:

<Tabs>
  <Tab title="OpenAI">
    ```json theme={null}
    {
      "input_tokens": 4305,
      "input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 4302, "cache_write_1h_tokens": 0, "audio_tokens": 0 },
      "output_tokens": 25,
      "output_tokens_details": { "reasoning_tokens": 0 },
      "total_tokens": 4330,
      "byok_used": false, "fallback_triggered": false
    }
    ```

    On this endpoint, an identical repeat can report another full cache write rather than a cache read.
  </Tab>

  <Tab title="Anthropic (Bedrock)">
    Claude models are answered through MeshAPI's translation, so they carry the same cache breakdown as on Chat Completions. This is a cache write with a 1-hour TTL:

    ```json theme={null}
    {
      "input_tokens": 4701,
      "input_tokens_details": { "cached_tokens": 0, "cache_write_tokens": 4686, "cache_write_1h_tokens": 4686, "audio_tokens": 0 },
      "output_tokens": 29,
      "output_tokens_details": { "reasoning_tokens": 0, "audio_tokens": 0, "accepted_prediction_tokens": 0, "rejected_prediction_tokens": 0 },
      "total_tokens": 4730,
      "byok_used": false, "fallback_triggered": false
    }
    ```

    A model answered through translation also carries the other Chat Completions counts in `output_tokens_details`.
  </Tab>

  <Tab title="xAI">
    `output_tokens` includes `reasoning_tokens` (221 = 21 + 200), and xAI's own keys are returned alongside:

    ```json theme={null}
    {
      "input_tokens": 4491,
      "input_tokens_details": { "cached_tokens": 128, "cache_write_tokens": 0, "cache_write_1h_tokens": 0, "audio_tokens": 0 },
      "output_tokens": 221,
      "output_tokens_details": { "reasoning_tokens": 200 },
      "total_tokens": 4712,
      "byok_used": false, "fallback_triggered": false,
      "num_sources_used": 0,
      "num_server_side_tools_used": 0,
      "context_details": { "input_tokens": 4491, "output_tokens": 229 }
    }
    ```
  </Tab>
</Tabs>

Not every route can serve the Responses API. One that can't returns `501 model_capability_not_supported` — for example, `google/gemini-2.5-flash` on the Vertex route.

`GET /v1/responses/{id}` returns the stored response as the provider kept it, so its usage is not in this format.

## Messages API

Every [`POST /v1/messages`](/docs/capabilities/messages-api) response returns these keys, in Anthropic's format:

```json theme={null}
{
  "input_tokens": 15,
  "cache_creation_input_tokens": 4686,
  "cache_read_input_tokens": 0,
  "cache_creation": {
    "ephemeral_5m_input_tokens": 0,
    "ephemeral_1h_input_tokens": 4686
  },
  "output_tokens": 29,
  "byok_used": false,
  "fallback_triggered": false
}
```

| Field | Meaning |
| - | - |
| `input_tokens` | Only **uncached** input |
| `cache_creation_input_tokens` | Input tokens written to the prompt cache, all TTLs combined |
| `cache_read_input_tokens` | Input tokens read from the prompt cache |
| `cache_creation.ephemeral_5m_input_tokens` / `ephemeral_1h_input_tokens` | `cache_creation_input_tokens`, split by TTL |
| `output_tokens` | Output tokens |
| `byok_used`, `fallback_triggered` | As on Chat Completions |

All of these are present on every response, and `0` when unused. A cache read:

```json theme={null}
{
  "input_tokens": 15,
  "cache_creation_input_tokens": 0,
  "cache_read_input_tokens": 4689,
  "cache_creation": { "ephemeral_5m_input_tokens": 0, "ephemeral_1h_input_tokens": 0 },
  "output_tokens": 29,
  "byok_used": false, "fallback_triggered": false
}
```

Total input is `input_tokens + cache_creation_input_tokens + cache_read_input_tokens`. Don't apply this on a [gateway cache hit](#gateway-cache-hits), where `input_tokens` already holds the whole input.

On a stream, the counts arrive on `message_delta`. `message_start` carries the same fixed keys as zeros — see [Messages API](/docs/capabilities/messages-api). Provider keys are returned on the response body and on `message_delta`.

## Summary

| | Chat Completions | Responses API | Messages API |
| - | - | - | - |
| Usage format | Chat Completions, fixed keys | OpenAI Responses, fixed keys | Anthropic Messages, fixed keys |
| Input total | `prompt_tokens` (includes cache reads and writes) | `input_tokens` (includes cache reads and writes) | `input_tokens + cache_creation_input_tokens + cache_read_input_tokens` |
| Cache read | `prompt_tokens_details.cached_tokens` | `input_tokens_details.cached_tokens` | `cache_read_input_tokens` |
| Cache write | `prompt_tokens_details.cache_write_tokens` | `input_tokens_details.cache_write_tokens` | `cache_creation_input_tokens` |
| 1-hour cache write | `prompt_tokens_details.cache_write_1h_tokens` | `input_tokens_details.cache_write_1h_tokens` | `cache_creation.ephemeral_1h_input_tokens` |
| Reasoning | `completion_tokens_details.reasoning_tokens` | `output_tokens_details.reasoning_tokens` | Not returned |
| Provider keys | Returned alongside | Returned alongside | Returned alongside |
| Gateway cache hit | `X-Cache: HIT`, not billed, cache counts `0` | `X-Cache: HIT`, not billed, cache counts `0` | `X-Cache: HIT`, not billed, whole input in `input_tokens` |

<Note>
  Usage tells you what was processed, not what you were charged. For the exact charge of a request, read `event.cost_usd` from [`GET /v1/usage/requests/{request_id}`](/api/usage/get-request). That endpoint returns no per-request cache fields, so record `usage` from the response if you need them.
</Note>

## Related

* [Caching](/docs/capabilities/caching) — the gateway response cache and provider prompt caching, and what each costs
* [Usage & Monitoring API](/docs/reference/usage-api) — usage, spend and per-request history
* [Pricing](/docs/getting-started/pricing) — how cached tokens are billed


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.