API de consumo

Lee por HTTP lo que se ha gastado, con un token con alcance, por mensaje, por llamada al modelo, con o sin tu markup.

/v1/usage es sobre lo que construyes una integración de facturación: lee lo que se ha gastado, por HTTP, con un token que ve las cifras pero no ejecuta nada. Responde a la pregunta que la facturación hace de verdad, que no es “cuánto costó este mes”, sino “cuánto costó ese mensaje, y por qué”.

Cuatro endpoints, cuatro niveles de detalle sobre el mismo ledger:

Endpoint Una fila por
GET /v1/usage intervalo de tiempo (hora, día, semana, mes, año)
GET /v1/usage/events llamada al modelo
GET /v1/usage/runs mensaje entrante
GET /v1/usage/runs/:id ese mensaje, llamada a llamada

Usan la misma cabecera Authorization: Bearer pepe_... que el resto de la API HTTP y solo responden sobre los proyectos que el token alcanza. Consulta Facturación y límites para ver cómo se calculan las cifras.

Un token que solo lee

Un token puede ejecutar agentes y no puede leer el consumo salvo que lo indiques, así que nada de lo que ya has creado cambia. Crea un token de facturación de solo lectura así:

pepe token add --project acme --no-chat --usage --prices billable --label "facturación acme"

Ese token llama a /v1/usage, no llama a /v1/chat/completions, ve solo el proyecto acme y ve solo lo que paga el cliente. Entrégalo al sistema financiero del cliente sin darle además una credencial capaz de gastar tu presupuesto de modelo.

Los cuatro permisos:

Flag Por defecto Qué concede
--chat / --no-chat activado ejecutar agentes (/v1/chat/completions, el WebSocket)
--usage desactivado leer /v1/usage
--prices billable cuánto de los importes muestra una lectura
--content desactivado el detalle de una ejecución puede incluir el prompt y los argumentos y la salida de las herramientas

Cámbialos después sin rotar el secreto, para que la integración del cliente siga funcionando mientras cambia lo que puede ver:

pepe token permissions abc123 --prices list
pepe token permissions abc123 --no-usage

Los mismos campos están en las tarjetas de token del panel, en Tokens, y un agente de confianza con la herramienta manage_token puede crear uno desde la conversación. Un token de widget nunca puede leer el consumo: vive en el código fuente público de la página.

Cuánto ve de los importes

Cada llamada medida tiene tres cifras, y --prices elige cuál de ellas devuelve una lectura:

billable y list son excluyentes, no acumulativos. Mostrar los dos revelaría la relación entre ellos, y esa relación es tu markup, tu margen. Un token con list ve precios de tarifa en lugar de, no además.

Esto lo decide el token, nunca la petición. Un cliente que llama a ?prices=all recibe la vista de su propio token, no la que pidió.

Agregados

curl -H "Authorization: Bearer $TOKEN" \
  "https://pepe.ejemplo.com/v1/usage?granularity=day&limit=30"
{
  "object": "usage.summary",
  "granularity": "day",
  "currency": "EUR",
  "scope": { "projects": ["acme"], "agent": null },
  "period": { "from": 1777536000, "to": null },
  "totals": { "calls": 412, "input_tokens": 918204, "output_tokens": 61233, "total_tokens": 979437, "billable": 13.55 },
  "buckets": [{ "key": "2026-07-28", "calls": 61, "input_tokens": 140233, "output_tokens": 9120, "total_tokens": 149353, "billable": 2.06 }],
  "by_model": [],
  "by_agent": [],
  "by_project": []
}

granularity es hour, day, week, month o year, y limit limita cuántos intervalos vuelven (60 por defecto).

Un agregado tiene que leer cada entrada de la ventana para sumarla, así que, sin from, este endpoint asume los últimos 90 días en lugar de todo el historial. La ventana usada vuelve en period, para que un informe nunca cubra menos de lo que crees, en silencio. Pide más cuando lo necesites: from=0 es todo. Un token all recibe además subscriptions y margin en el nivel superior, y un markup en cada entrada de by_project.

Una fila por llamada al modelo

curl -H "Authorization: Bearer $TOKEN" \
  "https://pepe.ejemplo.com/v1/usage/events?session=telegram:12345&limit=100"
{
  "object": "list",
  "data": [
    {
      "at": 1785312000,
      "project": "acme",
      "agent": "acme/ventas",
      "model": "gpt-4o",
      "run_id": "1785312000123456",
      "session": "telegram:12345",
      "source": "telegram",
      "input_tokens": 4120,
      "output_tokens": 210,
      "cached_input_tokens": 3072,
      "total_tokens": 4330,
      "subscription": false,
      "billable": 0.0231
    }
  ],
  "has_more": true,
  "next_cursor": 84213
}

Devuelve next_cursor como cursor para pedir la página siguiente. La paginación usa un id opaco de fila en lugar del timestamp, porque at tiene granularidad de un segundo y un salto de página que caiga dentro de un segundo con mucha actividad perdería filas o las repetiría.

Una fila por mensaje

Es el endpoint que quiere la mayoría de las integraciones. Un solo mensaje entrante suele costar varias llamadas al modelo: el agente responde, llama a una herramienta, recibe el resultado, llama a otra y responde de nuevo. /v1/usage/runs reagrupa esas llamadas en el mensaje que las provocó.

curl -H "Authorization: Bearer $TOKEN" "https://pepe.ejemplo.com/v1/usage/runs?limit=50"
{
  "object": "list",
  "data": [
    {
      "id": "1785312000123456",
      "at": 1785312000,
      "project": "acme",
      "agent": "acme/ventas",
      "session": "telegram:12345",
      "source": "telegram",
      "ms": 8412,
      "outcome": "ok",
      "tools": ["web_search", "fetch_url", "write_file"],
      "tool_calls": 3,
      "calls": 4,
      "input_tokens": 18320,
      "output_tokens": 940,
      "total_tokens": 19260,
      "billable": 0.0912
    }
  ],
  "has_more": false,
  "next_cursor": null
}

source es lo que disparó la ejecución (telegram, api, cron, flow, etc.), outcome es ok o error, y ms es lo que tardó el mensaje completo.

Fíjate en lo que dicen juntos calls: 4 y tool_calls: 3. Una herramienta no cuesta tokens por sí misma; lo que encarece un mensaje es el número de llamadas al modelo, porque cada iteración reenvía un contexto que el resultado de la herramienta anterior acaba de agrandar. Por eso la ejecución, y no la herramienta, es la unidad que vale la pena leer.

Un mensaje, llamada a llamada

curl -H "Authorization: Bearer $TOKEN" \
  "https://pepe.ejemplo.com/v1/usage/runs/1785312000123456"

Devuelve los mismos campos que la fila de la lista, más breakdown: cada llamada al modelo de esa ejecución, en orden, con sus propios tokens, aciertos de caché e importes. Es la respuesta a “por qué costó tanto este mensaje”.

Un token creado con --content recibe además un objeto content con el prompt y los argumentos y la salida de cada herramienta. Sin él no existe siquiera la clave content. Desactivado por defecto a propósito: un informe de consumo es una factura, y una factura no es una transcripción. El contenido viene también del trace de la ejecución, que se recorta por proyecto, así que una ejecución lo bastante antigua devuelve content: null en lugar de fingir que nunca lo tuvo.

Filtros

Cada endpoint acepta los que tienen sentido para él:

Parámetro Dónde Significado
project todos un proyecto, y solo uno que el token ya alcanza
agent todos el gasto de un agente
model resumen, eventos una conexión de modelo
source todos telegram, api, cron, flow, …
session todos una conversación
run_id resumen, eventos las llamadas de un mensaje
from / to todos segundos unix, [from, to)
limit todos tamaño de página (máx. 1000)
cursor eventos, ejecuciones el next_cursor de la página anterior
granularity resumen hour, day, week, month, year

Un filtro solo puede estrechar lo que el token ya alcanza. Nombrar un proyecto fuera de su alcance es 403, no un resultado vacío, y un token fijado a un agente sigue en ese agente, diga lo que diga agent=. model= y run_id= en /runs son 400: una ejecución no tiene un único modelo, un id de ejecución es para /runs/:id, y un filtro que en silencio no hace nada devuelve un informe que creerías más estrecho de lo que es.

Errores

Estado Cuándo
401 token ausente o desconocido
403 el token no puede leer el consumo, o pidió un proyecto que no alcanza
404 no existe esa ejecución dentro del alcance del token
400 un parámetro inservible

Una ejecución de otro proyecto responde 404 en lugar de 403, para que el endpoint nunca confirme que un id existe en algún sitio que no puedes ver.