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

# Uso de tokens

Cada respuesta de LLM lleva un objeto `usage` que informa los tokens que consumió la solicitud. Sunra informa el uso con la semántica del endpoint que usted llamó: una respuesta Messages sigue el contrato de Anthropic, y una respuesta Chat Completions o Responses sigue el contrato de OpenAI.

Estas formas difieren de manera deliberada. Un SDK de OpenAI que lee una respuesta Chat Completions asume la semántica de OpenAI, y un SDK de Anthropic que lee una respuesta Messages asume la semántica de Anthropic. Cada endpoint respeta lo que promete su propia especificación en lugar de verse forzado a una única forma compartida.

| Endpoint               | Campo de conteo del prompt | ¿Los tokens en caché están incluidos en él?                                        |
| ---------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
| `/v1/messages`         | `input_tokens`             | No — los tres buckets de entrada son mutuamente excluyentes                        |
| `/v1/chat/completions` | `prompt_tokens`            | Sí — los tokens en caché son un subconjunto, detallados en `prompt_tokens_details` |
| `/v1/responses`        | `input_tokens`             | Sí — los tokens en caché son un subconjunto, detallados en `input_tokens_details`  |

<Warning>
  `/v1/messages` y `/v1/responses` usan ambos el nombre de campo `input_tokens`, y no significa lo mismo en los dos. En Messages es únicamente la entrada nueva. En Responses es el prompt completo, incluidos los tokens en caché.
</Warning>

## Messages

En `/v1/messages`, los tres buckets de entrada son **mutuamente excluyentes**. Ningún token se cuenta dos veces, por lo que el total del prompt es su suma:

```
total prompt = input_tokens + cache_creation_input_tokens + cache_read_input_tokens
```

<ResponseField name="input_tokens" type="integer">
  Únicamente tokens de entrada nuevos. Excluye ambos buckets de caché.
</ResponseField>

<ResponseField name="cache_creation_input_tokens" type="integer">
  Tokens escritos en la caché por esta solicitud.
</ResponseField>

<ResponseField name="cache_read_input_tokens" type="integer">
  Tokens servidos a esta solicitud desde la caché.
</ResponseField>

<ResponseField name="output_tokens" type="integer">
  Tokens generados por el modelo.
</ResponseField>

<ResponseField name="total_tokens" type="integer">
  Los tres buckets de entrada más `output_tokens`. Presente en respuestas sin streaming.
</ResponseField>

Un bucket ausente o `null` cuenta como cero.

### Ejemplo práctico

El mismo prefijo de 19.000 tokens enviado dos veces contra `claude-opus-4-8`. La primera solicitud escribe la caché; la segunda la lee.

```json Solicitud en frío (escritura de caché) theme={null}
{
  "usage": {
    "input_tokens": 8,
    "cache_creation_input_tokens": 19349,
    "cache_read_input_tokens": 0,
    "output_tokens": 2,
    "total_tokens": 19359,
    "sunra_usage_semantics": "anthropic.exclusive.v1"
  }
}
```

```json Solicitud en caliente (lectura de caché) theme={null}
{
  "usage": {
    "input_tokens": 8,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 19349,
    "output_tokens": 2,
    "total_tokens": 19359,
    "sunra_usage_semantics": "anthropic.exclusive.v1"
  }
}
```

`input_tokens` se mantiene en 8 en ambas solicitudes, porque 8 es la entrada genuinamente nueva cada vez. El prefijo de 19.349 tokens pasa del bucket de creación al bucket de lectura. Ambas solicitudes suman los mismos 19.359 tokens en total, pero no cuestan lo mismo: las escrituras de caché y las lecturas de caché se tarifican con sus propias tarifas por token, y por eso se informan como buckets separados.

## Chat Completions y Responses

Estos endpoints informan la semántica de OpenAI, sin cambios. El conteo del prompt es el prompt **completo**, y los tokens en caché son un **subconjunto** de él que se informa por separado.

```json /v1/chat/completions theme={null}
{
  "usage": {
    "prompt_tokens": 19357,
    "completion_tokens": 2,
    "total_tokens": 19359,
    "prompt_tokens_details": {
      "cached_tokens": 19349
    }
  }
}
```

Sumar `prompt_tokens` y `cached_tokens` cuenta doble. Para obtener la entrada nueva en estos endpoints, reste:

```
fresh input = prompt_tokens - prompt_tokens_details.cached_tokens
```

La misma regla se aplica a `/v1/responses` con `input_tokens` e `input_tokens_details.cached_tokens`.

## El marcador `sunra_usage_semantics`

Las respuestas que Sunra ha normalizado llevan un marcador dentro de `usage`:

```json theme={null}
"sunra_usage_semantics": "anthropic.exclusive.v1"
```

El marcador es una promesa sobre la **respuesta**, no sobre ningún evento o campo concreto. En una respuesta sin streaming aparece en el objeto `usage` raíz; en una respuesta con streaming aparece en `message_start`, el evento que lleva los buckets de entrada. Cuando está presente con este valor, se cumplen las garantías de esta página: los tres buckets de entrada son mutuamente excluyentes, y `total_tokens` — cuando está presente — es su suma más `output_tokens`.

**Su ausencia también es una promesa.** Sunra normaliza únicamente las formas de respuesta que ha medido. Cualquier otra cosa se reenvía sin modificar desde el proveedor upstream y se deja sin marcar, y una respuesta sin el marcador es una respuesta cuyos buckets Sunra no garantiza.

Compruebe el marcador en lugar de inspeccionar los números para adivinar qué convención sigue una respuesta. Deducir la convención a partir de la forma de la respuesta es justamente lo que este campo existe para reemplazar — una heurística como "los buckets deben ser excluyentes porque suman más que el conteo del prompt" se cumple en más de una convención y tarde o temprano leerá mal una respuesta.

```python theme={null}
usage = response["usage"]

if usage.get("sunra_usage_semantics") == "anthropic.exclusive.v1":
    total_prompt = (
        usage["input_tokens"]
        + usage.get("cache_creation_input_tokens", 0)
        + usage.get("cache_read_input_tokens", 0)
    )
else:
    # Not normalized by Sunra. Treat the upstream shape as unverified
    # and consult that provider's own documentation.
    total_prompt = None
```

Solo las respuestas de `/v1/messages` llevan alguna vez el marcador. Chat Completions y Responses siguen la especificación de OpenAI y no se marcan.

El valor está versionado. Un cambio incompatible en el significado de estos campos se publica bajo un valor nuevo, de modo que una comprobación de igualdad contra `anthropic.exclusive.v1` no empezará a leer silenciosamente un contrato distinto.

## Streaming

En una solicitud Messages con streaming, el uso llega repartido en dos eventos. `message_start` lleva el lado de la entrada y el marcador. El `message_delta` final lleva únicamente `output_tokens`. Compruebe el marcador en `message_start` y después fusione los dos eventos como de costumbre — aplicar el uso del evento posterior sobre el anterior — para llegar a los valores documentados arriba.

`total_tokens` se omite en las respuestas con streaming. Ningún evento individual conoce a la vez el lado de la entrada y el de la salida, por lo que cualquier total calculado a mitad del stream sería incorrecto. Sume usted mismo los buckets una vez que el stream haya terminado.

## Migración desde el comportamiento anterior

Sunra anteriormente reenviaba el objeto `usage` del upstream tal cual en `/v1/messages`. La capa de traducción que hay delante de algunos proveedores incorpora los tokens de creación de caché **dentro** de `input_tokens`, por lo que quien seguía el contrato de Anthropic y sumaba los tres buckets contaba dos veces los tokens de creación de caché.

* **Si suma los tres buckets**, tal como describe el contrato de Anthropic, ahora es correcto. No se requiere ningún cambio de su parte.
* **Si compensaba el comportamiento anterior** — restando usted mismo `cache_creation_input_tokens` de `input_tokens`, o haciendo ingeniería inversa de esa incorporación de alguna otra forma — **deténgase**. Esa corrección ahora resta tokens que ya estaban excluidos y subestimará su entrada.
* **Si lee `total_tokens`**, sigue informando el conteo completo: entrada nueva, ambos buckets de caché y salida.

Condicione el cambio al marcador en lugar de a una fecha de despliegue, de modo que la misma ruta de código sea correcta tanto con respuestas marcadas como sin marcar.
