Skip to content

Análises de Uso ​

Análises de Uso é um catálogo mais uma consulta declarativa para agentes e scripts. O chamador informa um conjunto de dados, medidas, dimensões, uma janela de tempo e filtros, todos chaves de um catálogo no servidor. O servidor resolve o escopo do chamador, escolhe a tabela com o grão certo e devolve uma tabela compacta. Não existe entrada SQL de nenhum tipo: chaves desconhecidas são recusadas antes de qualquer acesso ao banco.

Comece pelo catálogo e depois consulte. O catálogo mostra apenas o que a credencial atual pode ver:

sh
spai analytics catalog
spai analytics catalog --dataset usage

Conjuntos de dados ​

usage: consumo cobrado ​

Consumo cobrado da organização, sempre em preço de venda na moeda da organização (veja Preço é preço de venda).

MedidaO que conta
price_localValor cobrado em moeda local. Exige billing:read.
quantityQuantidade consumida na unidade do item. Exige uma única unidade por linha (veja abaixo).
billed_quantityQuantidade pela qual o preço foi multiplicado, na unidade billed_unit. Exige uma única unidade cobrada por linha (veja Quantidade faturada e arredondamento).
itemsLinhas de cobrança.
requestsRequisições cobradas. Uma requisição pode usar vários modelos, então não pode ser agrupada por modelo.
ttfb_p50_ms, ttfb_p95_msTempo até o primeiro byte, mediana e p95. Só dado bruto, máximo de 31 dias.

Dimensões: project, user, agent, model, charge_subtype, unit, pricing_rule, billed_unit. billed_unit existe só no dado bruto de itens, então uma consulta que a usa fica limitada a 31 dias.

As fontes são escolhidas automaticamente. Rollups diários cobrem até 400 dias; a tabela bruta de itens cobre 31 dias e sustenta as medidas de latência. Dias fechados vêm do rollup e o dia de hoje vem das tabelas transacionais com a mesma agregação.

quantity mistura unidades (tokens, caracteres, segundos), então cada linha precisa resolver para uma unidade: adicione unit ou charge_subtype às dimensões, ou filtre uma única unidade. Caso contrário a consulta é recusada com mixed_units e uma correção pronta. billed_quantity segue a mesma regra com billed_unit, unit ou charge_subtype.

charge_subtype aceita os tipos de uso gravados em cada item, como agent, speech-to-text e text-generation. O catálogo lista os valores que o token pode ver, e pricing_rule aceita as regras de preço do catálogo (por exemplo voice). Nomes legados como input_token continuam aceitos como filtro.

conversations: conversas por agente, canal e contato ​

Conversas (threads excluídas ficam de fora) com escalação para humano e custo cobrado.

MedidaO que conta
conversationsConversas iniciadas.
escalatedConversas com escalação para humano.
escalation_rateEscaladas divididas pelas conversas.
price_localValor cobrado por trás das conversas. Exige billing:read.
price_per_conversationValor cobrado dividido pelas conversas. Exige billing:read.

Dimensões: project, user, agent, channel, hour_of_day, contact.

A janela cobre até 92 dias. hour_of_day segue o fuso horário pedido; contact sai mascarado salvo se o chamador puder ler conversas (veja abaixo).

analysis: campos da análise pós-atendimento ​

Campos de uma análise estruturada viram entradas do catálogo tipadas pelo JSON schema dela: uma string com enum vira dimensão, um booleano vira dimensão mais uma medida .rate (fração de respostas verdadeiras), e um número vira medidas .avg, .min, .max e .count. Texto livre, arrays e objetos nunca são expostos. A consulta precisa referenciar exatamente um id de análise estruturada nas dimensões, medidas e filtros analysis.*.

Dimensões: project, agent, channel, mais uma entrada por campo exposto, chamada analysis.<id_da_analise_estruturada>.<campo>. A janela cobre até 183 dias.

Quantidade faturada e arredondamento ​

billed_quantity é a quantidade pela qual o preço foi multiplicado, então pode diferir da quantity medida. O arredondamento depende do produto:

  • Agente de voz (charge_subtype agent, regra de preço voice): cobrado por sessão em blocos de 60 segundos, arredondados para cima, com mínimo de 1 segundo. Uma sessão de 1 segundo cobra 1 minuto, 61 segundos cobra 2 minutos e 95 segundos cobra 2 minutos. billed_unit é minute.
  • Demais produtos: seguem a regra de preço do modelo ou serviço usado. Uma regra cobrada em blocos informa os blocos cobrados (por exemplo, um modelo de transcrição cobrado por minuto iniciado informa minute); qualquer outra regra informa a quantidade cobrada, então billed_quantity é igual a quantity e billed_unit é igual a unit (token, character, second, ...).

Leia sempre billed_unit junto com billed_quantity: é a unidade sobre a qual o preço foi aplicado.

O consumo registrado antes de existir a quantidade faturada não é preenchido retroativamente, então períodos anteriores a essa mudança mostram um billed_quantity menor ou vazio. Use quantity para esses períodos.

Janelas de tempo e limites ​

json
{
  "dataset": "usage",
  "measures": ["price_local"],
  "dimensions": ["model"],
  "time": { "range": "last_56d", "granularity": "week", "tz": "America/Sao_Paulo" },
  "filters": [{ "dim": "charge_subtype", "op": "in", "values": ["input_token", "output_token"] }],
  "limit": 200
}
  • range: last_<N>d com N de 1 a 400, this_month, last_month, ou um { "from": "YYYY-MM-DD", "to": "YYYY-MM-DD" } explícito. Padrão last_30d. As janelas são dias UTC inteiros, exceto no caminho de tz exato abaixo, onde os dias são dias locais no tz. to é limitado ao dia de hoje.
  • granularity: none, day, week ou month. Padrão none. A coluna period traz a data de início do intervalo em YYYY-MM-DD (a semana começa na segunda-feira, o mês no dia 1). Sem order, as linhas saem por período crescente e depois pela primeira medida decrescente.
  • tz: um nome IANA, padrão UTC. Ele muda o agrupamento das fontes brutas e a dimensão hour_of_day. Para usage com fuso diferente de UTC:
    • Até 31 dias (uma janela de compare conta em dobro), com todas as medidas, dimensões e filtros escolhidos servidos pelos itens brutos: os limites de dia e de mês são calculados no fuso, com horário de verão respeitado em cada limite, e nenhum aviso rollup_utc_days é devolvido. Os itens brutos servem price_local, quantity, billed_quantity, items, ttfb_p50_ms, ttfb_p95_ms, project, user, model, charge_subtype, unit, pricing_rule e billed_unit.
    • Janelas maiores, ou uma consulta que usa agent ou requests: os rollups agrupam por dia UTC, e uma granularidade de tempo soma um aviso rollup_utc_days.
  • No máximo 6 medidas, 3 dimensões e 10 filtros por consulta. Chaves desconhecidas são recusadas.
  • No máximo 5000 linhas; linhas extras marcam truncated: true com um aviso truncated. O limite padrão é 200.
  • Toda consulta roda sob um teto de 5 segundos.
  • Janela máxima por seleção: 400 dias nos rollups, 92 dias nas conversas, 183 dias na análise, 31 dias no dado bruto de itens.

compare: "previous_period" roda a mesma consulta na janela anterior e junta as linhas pelas dimensões. Funciona só com granularity: "none". Para uma série temporal, amplie a janela em vez de comparar.

Dimensões de entidade (project, agent, user) agrupam por id e emitem duas colunas: <dim> com o nome de exibição e <dim>_id com o id.

As respostas trazem meta.warnings com códigos como partial_last_period (a janela termina hoje e o último intervalo está incompleto), rollup_utc_days, contact_masked e truncated.

Mascaramento de contato ​

contact agrupa pelo identificador completo mas imprime mascarado, salvo se o chamador tiver acesso de leitura às conversas (no OAuth, também o escopo spai:threads:read). Filtrar por contact sem esse acesso é recusado com forbidden_dimension em vez de devolver linhas mascaradas.

Preço é preço de venda ​

price_local é sempre o preço de venda na moeda da organização. Custo nunca está disponível: nenhuma medida, dimensão ou filtro expõe custo, margem ou tabelas de tarifa. Pedir uma medida parecida com custo responde unknown_measure e aponta para price_local; nunca confirma se tal coluna existe.

Erros ​

CódigoStatusQuando
analytics_invalid_query400Forma ruim ou chave desconhecida. details.reason nomeia a causa: unknown_dataset, unknown_measure, unknown_dimension, invalid_filter, invalid_filter_value, invalid_granularity, invalid_order, invalid_limit, too_many_measures, too_many_dimensions, incompatible_selection, mixed_units, range_too_large ou invalid_query. details também traz available, allowed ou fix quando útil.
analytics_forbidden403forbidden_measure (medida de gasto sem billing:read) ou forbidden_dimension (contato sem leitura de conversas).
analytics_query_timeout422O teto de 5 segundos foi atingido. Reduza a janela ou tire dimensões.
analytics_busy429Mais de 2 consultas de análises já rodam para a organização. Aguarde e tente de novo.
analytics_unavailable503A fonte de dados de análises não está configurada.

Um valor fora do escopo do chamador (id ou nome de projeto, agente, usuário ou contato de outro projeto ou organização, ou que não existe) sempre responde invalid_filter_value com allowed listando os valores do escopo do chamador, de modo que entidades fora do escopo são indistinguíveis das inexistentes.

Escopo OAuth ​

spai:analytics:read é um escopo de leitura para os recursos de API e MCP. Ele mapeia para dashboard:read, nunca cobra, e está incluído no login padrão da CLI, no login somente leitura e nos escopos anunciados do MCP. Concessões existentes não ganham o escopo no refresh: entre de novo para autorizá-lo. Veja Autenticar com OAuth.

Ferramentas MCP ​

FerramentaO que fazEscopo
analytics_catalogLista conjuntos, medidas, dimensões, valores permitidos e limites para o tokenspai:analytics:read
analytics_queryRoda uma consulta declarativa. Nunca aceita SQL.spai:analytics:read

As duas ferramentas são somente leitura. Uma consulta com falha devolve um erro de ferramenta com code, message e details estruturados (por exemplo analytics_invalid_query com reason e fix), para o agente se corrigir em vez de adivinhar.

Exemplos de CLI ​

Comandos de análises exigem spai:analytics:read. Uma sessão sem ele falha antes de qualquer requisição com a correção:

text
This command needs spai:analytics:read. Run: spai auth login

Com uma chave API não há verificação local de escopo.

Gasto semanal de LLM por modelo, renderizado como spec de gráfico:

sh
spai analytics query usage \
  --measure price_local \
  --dimension model \
  --range last_56d \
  --granularity week \
  --tz America/Sao_Paulo \
  --filter 'charge_subtype in input_token,output_token' \
  --vega > spend.vl.json

Custo por conversa por agente, comparado com os 30 dias anteriores:

sh
spai analytics query conversations \
  --measure price_per_conversation,conversations \
  --dimension agent \
  --range last_30d \
  --compare previous_period

Escalação por hora do dia, para dimensionar a equipe humana:

sh
spai analytics query conversations \
  --measure escalated,escalation_rate \
  --dimension hour_of_day \
  --range last_30d \
  --tz America/Sao_Paulo \
  --order hour_of_day:asc

Taxa de resolução e CSAT médio por motivo de contato, enviados de um arquivo em CSV:

sh
spai analytics query --file query.json --format csv

com query.json guardando a forma exata da consulta:

json
{
  "dataset": "analysis",
  "measures": ["analysis.support_review.resolved.rate", "analysis.support_review.csat.avg", "conversations"],
  "dimensions": ["analysis.support_review.reason"],
  "time": { "range": "last_30d" },
  "order": [{ "by": "conversations", "dir": "desc" }]
}

support_review é um exemplo de id de análise estruturada vindo do catálogo: chame GET /v1/analytics/catalog (ou spai analytics catalog --dataset analysis) para listar os ids visíveis para o token, e use exatamente um id nas dimensões, medidas e filtros.

--file é mutuamente exclusivo com as flags de construção da consulta. Em pipes o formato padrão é JSON; --format table|json|csv escolhe a saída, e --vega imprime uma spec Vega-Lite v5 com os dados embutidos. Erros de uso saem com código 2 e erros do servidor imprimem código, mensagem e detalhes no stderr.

Exemplo REST ​

bash
curl -X POST "https://api.sippulse.ai/v1/analytics/query" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "dataset": "conversations",
    "measures": ["escalation_rate", "conversations"],
    "dimensions": ["channel"],
    "time": { "range": "last_30d" },
    "order": [{ "by": "escalation_rate", "dir": "desc" }]
  }'

Chame GET /v1/analytics/catalog antes para listar os conjuntos, medidas, dimensões e limites visíveis para o token. As respostas usam Cache-Control: no-store.

Minutos cobrados por projeto em um mês ​

Minutos de agente e minutos de transcrição por projeto em setembro de 2026, no horário de São Paulo. Cada linha traz uma única unidade, então a consulta agrupa por billed_unit: as linhas de agente vêm em minute, e as linhas de transcrição vêm na unidade da regra de preço do modelo de transcrição (minute para regras por minuto, second para regras por segundo).

bash
curl -X POST "https://api.sippulse.ai/v1/analytics/query" \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "dataset": "usage",
    "measures": ["billed_quantity"],
    "dimensions": ["project", "charge_subtype", "billed_unit"],
    "filters": [{ "dim": "charge_subtype", "op": "in", "values": ["agent", "speech-to-text"] }],
    "time": { "range": { "from": "2026-09-01", "to": "2026-09-30" }, "tz": "America/Sao_Paulo" },
    "order": [{ "by": "billed_quantity", "dir": "desc" }]
  }'

A janela tem 30 dias, então a consulta lê os itens brutos com limites de dia em America/Sao_Paulo e não devolve o aviso rollup_utc_days.