API de consumo

Leia por HTTP quanto foi gasto, com um token de escopo restrito, por mensagem, por chamada de modelo, com ou sem o seu markup aplicado.

É em cima do /v1/usage que você constrói uma integração de cobrança: ele lê o que já foi gasto, via HTTP, com um token que enxerga os números mas não roda nada. A pergunta que a cobrança realmente faz não é “quanto custou esse mês”, e sim “quanto custou aquela mensagem ali, e por quê”; é essa que o endpoint responde.

São quatro endpoints, quatro níveis de zoom sobre o mesmo livro-razão:

Endpoint Uma linha por
GET /v1/usage intervalo de tempo (hora, dia, semana, mês, ano)
GET /v1/usage/events chamada de modelo
GET /v1/usage/runs mensagem recebida
GET /v1/usage/runs/:id aquela mensagem, chamada por chamada

Todos usam o mesmo cabeçalho Authorization: Bearer pepe_... do resto da API HTTP, e só devolvem dados dos projetos que o token consegue alcançar. Para entender como os números por trás disso são calculados, veja Cobrança e limites.

Um token que só lê

Por padrão, um token pode rodar agentes mas não consegue ler consumo, a menos que você libere isso explicitamente, então nada do que já foi emitido muda de comportamento. Um token de cobrança somente leitura se cria assim:

pepe token add --project acme --no-chat --usage --prices billable --label "cobrança acme"

Com ele dá para chamar /v1/usage, mas não /v1/chat/completions; ele enxerga só o projeto acme, e só o valor que o cliente efetivamente paga. Dá para entregar isso ao financeiro de um cliente sem junto entregar uma credencial capaz de gastar o seu orçamento de modelo.

As quatro permissões:

Flag Padrão O que libera
--chat / --no-chat ligado rodar agentes (/v1/chat/completions, o WebSocket)
--usage desligado ler o /v1/usage
--prices billable quanto dos valores uma leitura revela
--content desligado o detalhe de uma execução pode trazer junto o prompt e os argumentos/saída das ferramentas

Dá para mudar isso depois sem rotacionar o segredo, então a integração do cliente continua funcionando o tempo todo, mesmo enquanto o que ela enxerga muda:

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

Esses mesmos campos aparecem nos cards de token do painel, em Tokens, e um agente de confiança com a ferramenta manage_token também consegue criar um direto pela conversa. Um token de widget, por outro lado, nunca lê consumo: ele fica exposto no código-fonte público de uma página.

Quanto ele consegue ver dos valores

Toda chamada medida guarda três números, e é o --prices que decide qual deles uma leitura devolve:

billable e list se excluem, não se somam: mostrar os dois ao mesmo tempo revelaria a razão entre eles, e essa razão é justamente o seu markup, a sua margem. Um token com permissão list vê preço de tabela no lugar do billable, nunca os dois.

Quem decide qual desses três aparece é o token, nunca a requisição: um cliente que chama ?prices=all recebe de volta a visão que o próprio token tem, e não a que pediu na URL.

Agregados

curl -H "Authorization: Bearer $TOKEN" \
  "https://pepe.exemplo.com/v1/usage?granularity=day&limit=30"
{
  "object": "usage.summary",
  "granularity": "day",
  "currency": "BRL",
  "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 aceita hour, day, week, month ou year, e limit define quantos intervalos voltam na resposta (60 por padrão).

Somar um agregado exige ler cada entrada da janela inteira, então, sem um from explícito, o endpoint assume os últimos 90 dias em vez do histórico completo. A janela realmente usada volta no campo period, então nenhum relatório acaba cobrindo, em silêncio, menos período do que você imagina. Peça mais quando precisar: from=0 traz tudo. Um token com permissão all ganha ainda subscriptions e margin no nível raiz, além de um markup em cada entrada de by_project.

Uma linha por chamada de modelo

curl -H "Authorization: Bearer $TOKEN" \
  "https://pepe.exemplo.com/v1/usage/events?session=telegram:12345&limit=100"
{
  "object": "list",
  "data": [
    {
      "at": 1785312000,
      "project": "acme",
      "agent": "acme/vendas",
      "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
}

Para a próxima página, devolva o next_cursor recebido como cursor na próxima chamada. A paginação roda sobre um id opaco de linha em vez do timestamp porque at só tem granularidade de um segundo, e uma virada de página caindo bem dentro de um segundo movimentado acabaria perdendo linhas ou repetindo elas.

Uma linha por mensagem

Esse é o endpoint que a maioria das integrações realmente quer. Uma única mensagem recebida costuma gerar várias chamadas de modelo: o agente responde, chama uma ferramenta, recebe o resultado dela, chama outra, e só então responde de novo. O /v1/usage/runs reúne todas essas chamadas de volta na mensagem que as originou.

curl -H "Authorization: Bearer $TOKEN" "https://pepe.exemplo.com/v1/usage/runs?limit=50"
{
  "object": "list",
  "data": [
    {
      "id": "1785312000123456",
      "at": 1785312000,
      "project": "acme",
      "agent": "acme/vendas",
      "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 indica o que disparou a execução (telegram, api, cron, flow, e por aí vai), outcome é ok ou error, e ms mostra quanto tempo a mensagem inteira levou.

Vale reparar no que calls: 4 e tool_calls: 3 dizem juntos: uma ferramenta em si não custa tokens; o que encarece uma mensagem é o número de chamadas de modelo, já que cada nova iteração reenvia um contexto que o resultado da ferramenta anterior acabou de deixar maior. É exatamente por isso que a execução, e não a ferramenta isolada, é a unidade que vale a pena olhar.

Uma mensagem, chamada por chamada

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

Devolve os mesmos campos da linha de lista, mais um breakdown: cada chamada de modelo daquela execução, na ordem em que aconteceu, com tokens, acertos de cache e valores próprios. É essa a resposta para “por que essa mensagem custou o que custou”.

Um token criado com --content recebe também um objeto content, trazendo o prompt e os argumentos/saída de cada ferramenta usada. Sem essa flag, a chave content nem aparece. Isso vem desligado por padrão de propósito: um relatório de consumo é uma fatura, não uma transcrição da conversa. Esse conteúdo vem do trace da execução, que é podado por projeto ao longo do tempo, então uma execução velha o bastante devolve content: null em vez de fingir que nunca teve conteúdo algum.

Filtros

Cada endpoint aceita os filtros que fazem sentido para ele:

Parâmetro Onde Significado
project todos um projeto, e só um que o token já alcança
agent todos o gasto de um agente
model resumo, eventos uma conexão de modelo
source todos telegram, api, cron, flow, …
session todos uma conversa
run_id resumo, eventos as chamadas de uma mensagem
from / to todos segundos unix, [from, to)
limit todos tamanho da página (máx. 1000)
cursor eventos, execuções o next_cursor da página anterior
granularity resumo hour, day, week, month, year

Um filtro só consegue estreitar o que o token já alcançava, nunca ampliar. Nomear um projeto fora do escopo dele resulta em 403, não num resultado vazio, e um token travado a um único agente continua restrito a ele independente do que agent= disser na URL. Já model= e run_id= em /runs dão 400: uma execução não tem um único modelo associado, e um id de execução específico é papel do /runs/:id; um filtro que simplesmente não faz nada devolveria um relatório que você acreditaria mais restrito do que realmente é.

Erros

Status Quando
401 token ausente ou desconhecido
403 o token não tem permissão de leitura de consumo, ou pediu um projeto fora do seu alcance
404 não existe essa execução dentro do escopo do token
400 um parâmetro inutilizável

Uma execução pertencente a outro projeto responde 404, não 403, para que o endpoint nunca confirme que um id existe em algum lugar que você não tem como enxergar.