Documentación

Documentación

API de uso

Consulta los recuentos de tokens y el coste de la clave de API que realiza la solicitud. Cada clave solo puede acceder a sus propios datos. Usa este endpoint para alimentar tus paneles de facturación, conciliar los cargos mensuales o configurar alertas de costes.

GET /v1/usage devuelve los totales agregados de tokens y costes correspondientes a la clave de API del encabezado Authorization. Agrupa por día u hora; opcionalmente, desglosa por modelo. No se pueden consultar los datos de otra clave; para eso, inicia sesión en el panel.

Autenticación

Envía tu clave de API de Kunavo como token Bearer: debe ser la misma clave cuyo uso quieres consultar. El endpoint devuelve únicamente el uso facturado a esta clave concreta; no hay ningún parámetro para solicitar los datos de otra clave.

Usa una clave por proyecto. Se recomienda crear una clave de API distinta para cada aplicación que factures; así, los paneles de Kunavo y este endpoint agruparán los datos de forma natural «por proyecto». Administra las claves en /app/keys.

Solicitud

ParámetroObligatorioPredeterminadoNotas
start_dateyes—AAAA-MM-DD, UTC. Inclusivo. Debe ser ≤ la fecha de hoy (UTC).
end_dateyes—YYYY-MM-DD, UTC. Inclusiva. Una fecha posterior a hoy se interpreta como hoy; la respuesta repite el end_date utilizado.
bucketnodayUno de day, hour.
group_byno(none)Valores separados por comas. Admitidos: model. Omítelo para obtener una fila por intervalo.
Límites del intervalo. bucket=day admite hasta 90 días; bucket=hour, hasta 7 días. Si se supera el límite, la solicitud devuelve 400 invalid_request_error; divide el intervalo en varias llamadas.
Zona horaria. Los intervalos se alinean con los días y horas UTC. Si necesitas días de calendario según otra zona horaria, consulta los datos diarios y ajusta los extremos en el cliente. Un futuro parámetro tz= permitirá hacerlo en el servidor sin cambiar ningún campo existente.

Ejemplos

Totales diarios de los últimos 30 días, con todos los modelos agrupados:

usage_30d.sh
# Daily totals for the last 30 days
curl https://api.kunavo.com/v1/usage \
  -G \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  --data-urlencode "start_date=2026-04-28" \
  --data-urlencode "end_date=2026-05-27"

Una fila por día y modelo:

usage_by_model.sh
# Per-model daily breakdown — one row per (day, model)
curl https://api.kunavo.com/v1/usage \
  -G \
  -H "Authorization: Bearer $KUNAVO_API_KEY" \
  --data-urlencode "start_date=2026-05-01" \
  --data-urlencode "end_date=2026-05-27" \
  --data-urlencode "group_by=model"

Python: sumar el intervalo en una sola cifra:

usage_query.py
import os, datetime as dt, requests

today = dt.date.today()
start = today - dt.timedelta(days=29)  # last 30 days inclusive

r = requests.get(
    "https://api.kunavo.com/v1/usage",
    headers={"Authorization": f"Bearer {os.environ['KUNAVO_API_KEY']}"},
    params={
        "start_date": start.isoformat(),
        "end_date":   today.isoformat(),
        "group_by":   "model",
    },
    timeout=30,
)
r.raise_for_status()
body = r.json()

# body["data"] is one row per (day, model). Sum cost across the window:
total_usd = sum(float(row["cost_usd"]) for row in body["data"])
print(f"Spent ${total_usd:.4f} on key {body['api_key']['name']}")

Respuesta

200 OK: application/json con una lista de filas. Se omiten los intervalos sin actividad; el cliente completa los huecos si necesita una serie continua.

response.json
{
  "object": "list",
  "api_key": {
    "id": "k_abc123",
    "name": "production",
    "prefix": "sk-kn-aZ8x"
  },
  "start_date": "2026-05-01",
  "end_date":   "2026-05-27",
  "bucket": "day",
  "data": [
    {
      "bucket_start": "2026-05-01T00:00:00.000Z",
      "model": "claude-sonnet-4-6",
      "requests": 1284,
      "errors": 7,
      "input_tokens": 1532890,
      "output_tokens": 245100,
      "cached_input_tokens": 980000,
      "cache_write_tokens": 12000,
      "web_search_requests": 0,
      "cost_usd": "3.452100"
    },
    {
      "bucket_start": "2026-05-01T00:00:00.000Z",
      "model": "gpt-5",
      "requests": 88,
      "errors": 0,
      "input_tokens": 42000,
      "output_tokens": 12300,
      "cached_input_tokens": 0,
      "cache_write_tokens": 0,
      "web_search_requests": 0,
      "cost_usd": "0.210400"
    }
  ]
}
CampoTipoSignificado
bucket_startcadena (ISO 8601, UTC)Inicio del día o la hora que agrega esta fila.
modelstringIdentificador del modelo. Solo aparece si group_by=model.
requestsnumberLlamadas completadas correctamente en este intervalo.
errorsnumberLlamadas que terminaron con error, tiempo de espera agotado o cancelación. No se facturan.
input_tokensnumberTotal de tokens de entrada (incluye los subconjuntos de caché y escritura en caché).
output_tokensnumberTotal de tokens de salida.
cached_input_tokensnumberSubconjunto de input_tokens servido desde la caché de prompts del proveedor ascendente.
cache_write_tokensnumberTokens escritos en la caché de este intervalo (solo Anthropic; 0 en los demás).
web_search_requestsnumberBúsquedas web en el servidor, cada una facturada además de los tokens: las de Claude, mediante /v1/messages, y la herramienta web_search de OpenAI en un modelo GPT, mediante /v1/responses (0 en los demás casos).
cost_usdstringImporte cobrado en USD por este intervalo, con precisión de 6 decimales. Se devuelve como cadena para conservar la precisión; conviértelo sin perder precisión con parseFloat().
Por qué el coste es una cadena. Los costes ínfimos por llamada (unas pocas cienmilésimas de centavo en solicitudes con mucho uso de caché) se redondean a cero en IEEE-754 si se convierten directamente en una cadena. Mantener en la respuesta una cadena con 6 decimales permite que tu código de contabilidad la analice con precisión arbitraria (por ejemplo, Decimal()).

Caché del lado del cliente

El endpoint establece Cache-Control: private, max-age=60. La mayoría de los clientes (navegadores, solicitudes con una sesión y cualquier caché HTTP que uses) devolverán la misma respuesta para los mismos parámetros durante una ventana de 60 segundos; es adecuado para paneles que consultan periódicamente. Para forzar una lectura actualizada, cambia la cadena de consulta (por ejemplo, añade un parámetro para &_=ts evitar la caché) o envía Cache-Control: no-cache desde tu lado.

Errores

EstadoCódigoCuándo
401authentication_errorClave Bearer ausente, mal formada o revocada.
400invalid_request_errorFormato incorrecto de start_date/end_date, fecha final anterior a la inicial, un start_date posterior a hoy, intervalo superior al límite o valor de group_by no admitido.
500internal_errorBase de datos no disponible o fallo inesperado.

Advertencias

  • Claves eliminadas. Al revocar una clave de API, se elimina su api_key_id de las filas de uso anteriores (se establece en null), por lo que ya no se pueden recuperar los totales históricos mediante este endpoint. Los datos siguen disponibles en la vista agregada de la cuenta del panel. Si necesitas un registro de auditoría inmutable por clave, obtén y guarda los datos antes de revocarla.
  • Casi en tiempo real. Las filas aparecen a los pocos segundos de completarse la llamada correspondiente. No hay un límite garantizado de retraso; si necesitas que los datos coincidan exactamente con la factura, consulta una vez al día los datos de ayer en lugar de hacerlo minuto a minuto.
  • El coste es el importe facturado. El valor cost_usd coincide con el importe descontado de tu saldo. Ya incluye el mínimo de max(catalog, upstream × markup) descrito en Facturación. Esta respuesta no incluye una cifra de «coste mayorista» aparte.

Próximos pasos