Documentação

Documentação

API de uso

Consulte as contagens de tokens e o custo da chave de API usada na solicitação. Uma chave e seus próprios dados — sem acesso a outras chaves. Use isso para alimentar seus próprios painéis de cobrança, fazer conciliação mensal ou configurar alertas de custo.

GET /v1/usage retorna os totais agregados de tokens e custos da chave de API no cabeçalho Authorization. Agrupe por dia ou hora; opcionalmente, separe por modelo. Não é possível ler dados de outra chave — para isso, entre no painel.

Autenticação

Envie sua chave de API da Kunavo como um token Bearer, a mesma chave cujo uso você quer consultar. O endpoint retorna somente o uso cobrado nessa chave específica — não há parâmetro para solicitar dados de outra chave.

Considere um projeto por chave. O padrão recomendado é criar uma chave de API separada para cada aplicativo que você cobra — assim, os painéis da Kunavo e este endpoint consolidam os dados naturalmente "por projeto". Gerencie as chaves em /app/keys.

Solicitação

ParâmetroObrigatórioPadrãoObservações
start_dateyes—AAAA-MM-DD, UTC. Inclusivo. Deve ser ≤ hoje (UTC).
end_dateyes—AAAA-MM-DD, UTC. Inclusivo. Uma data posterior a hoje é interpretada como hoje; a resposta repete o end_date usado.
bucketnodayUm de day, hour.
group_byno(none)Separados por vírgulas. Compatíveis: model. Omita para obter uma linha por intervalo.
Limites do intervalo. bucket=day aceita até 90 dias; bucket=hour aceita até 7 dias. Acima desses limites, a solicitação retorna 400 invalid_request_error — divida-a em várias chamadas.
Fuso horário. Os intervalos são alinhados a dias/horas UTC. Se precisar de dias no horário local de outro fuso, consulte os dados por dia e ajuste os limites no cliente. Um parâmetro tz= futuro fará isso no servidor sem alterar nenhum campo existente.

Exemplos

Totais diários dos últimos 30 dias, agregados para todos os modelos:

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"

Uma linha por (dia, 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 — some o intervalo em um único número:

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']}")

Resposta

200 OK — application/json com uma lista de linhas. Intervalos sem atividade são omitidos; o cliente preenche as lacunas se precisar de uma série contínua.

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_startstring (ISO 8601, UTC)Início do dia ou da hora agregados nesta linha.
modelstringSlug do modelo. Presente apenas quando group_by=model.
requestsnumberChamadas concluídas com sucesso neste intervalo.
errorsnumberChamadas que terminaram em erro/timeout/cancelamento. Não são cobradas.
input_tokensnumberTotal de tokens de entrada (inclui os subconjuntos de cache e de gravação em cache).
output_tokensnumberTotal de tokens de saída.
cached_input_tokensnumberSubconjunto de input_tokens atendido pelo cache de prompt upstream.
cache_write_tokensnumberTokens gravados no cache deste intervalo (somente Anthropic; 0 nos demais).
web_search_requestsnumberPesquisas na web do lado do servidor, cada uma cobrada além dos tokens: as do Claude por meio de /v1/messages e a ferramenta web_search da OpenAI em um modelo GPT por meio de /v1/responses (0 nos demais casos).
cost_usdstringValor cobrado em USD neste intervalo, com precisão de 6 casas decimais. String para preservar a precisão; faça a conversão com segurança usando parseFloat().
Por que o custo é uma string. Custos minúsculos por chamada (alguns centésimos de milésimo de centavo para tráfego com muito uso de cache) são arredondados para zero pelo IEEE-754 quando convertidos em string de forma ingênua. Manter o formato de transmissão como string com 6 casas decimais permite que seu código contábil faça a conversão com precisão arbitrária (por exemplo, Decimal()).

Cache no cliente

O endpoint define Cache-Control: private, max-age=60. A maioria dos clientes (navegadores, solicitações com uma sessão e qualquer cache HTTP do seu lado) retornará a mesma resposta para os mesmos parâmetros em um intervalo de 60 segundos — adequado para painéis que consultam dados periodicamente. Para forçar uma leitura atualizada, altere a query string (por exemplo, adicione um parâmetro &_=ts para evitar o cache) ou envie Cache-Control: no-cache do seu lado.

Erros

StatusCódigoQuando
401authentication_errorChave Bearer ausente, malformada ou revogada.
400invalid_request_errorFormato inválido de start_date/end_date, fim anterior ao início, start_date posterior a hoje, intervalo acima do limite ou valor group_by incompatível.
500internal_errorBanco de dados inacessível ou falha inesperada.

Observações

  • Chaves excluídas. Quando você revoga uma chave de API, as linhas de uso anteriores perdem seu api_key_id (definido como null), portanto os totais históricos não podem mais ser recuperados por este endpoint. Os dados continuam disponíveis na visão agregada da sua conta no painel. Se precisar de um registro de auditoria imutável por chave, consulte e armazene os dados antes de revogá-la.
  • Quase em tempo real. As linhas aparecem poucos segundos após a conclusão da chamada correspondente. Não há um limite garantido para o atraso — se precisar de alinhamento exato com sua fatura, consulte os dados de ontem uma vez por dia, em vez de fazê-lo a cada minuto.
  • O custo é o valor cobrado. O cost_usd aqui corresponde ao valor debitado do saldo da sua carteira. Ele já reflete o piso de max(catalog, upstream × markup) descrito em Faturamento. Esta resposta não inclui um valor separado de "atacado".

Próximos passos