DEV Community

Cover image for Como Rastrear Gastos da API OpenAI por Funcionalidade: Guia de Atribuição de Custos
Lucas
Lucas

Posted on • Originally published at apidog.com

Como Rastrear Gastos da API OpenAI por Funcionalidade: Guia de Atribuição de Custos

Seu extrato do OpenAI diz que você gastou $4.237 no mês passado. Ele não informa que $3.100 vieram de um endpoint de sumarização descontrolado, $700 de um cliente que paga $50/mês e $437 de uma funcionalidade que ninguém usa. Para gerenciar custos de LLM em produção, você precisa atribuir cada requisição a uma funcionalidade, rota, cliente e ambiente — e transformar isso em logs, consultas, alertas e limites operacionais.

Experimente o Apidog hoje

💡 O Apidog ajuda a validar requisições em nível de API antes de você ir para produção. Use-o para reproduzir chamadas marcadas, verificar o formato dos logs e confirmar que cada requisição carrega os metadados esperados pelo seu data warehouse.

TL;DR

Implemente um wrapper único para chamadas OpenAI. Ele deve:

  • exigir metadados como feature, route, customer_id e environment;
  • capturar response.usage;
  • calcular cost_usd no momento da requisição;
  • emitir uma linha JSON estruturada por chamada;
  • enviar os eventos para seu data warehouse;
  • agregar custo por funcionalidade, rota e cliente;
  • aplicar limites por chave/projeto no painel do OpenAI;
  • validar o fluxo com testes de cenário no Apidog.

O problema: o painel de cobrança não responde à pergunta certa

O painel do OpenAI responde:

“Quanto minha organização gastou?”

Mas times de produto, engenharia e finanças precisam responder:

“Qual funcionalidade, cliente ou rota gerou esse gasto?”

Essa diferença importa quando você tem:

  • várias funcionalidades usando o mesmo modelo;
  • clientes B2B com padrões de uso diferentes;
  • jobs assíncronos ou cron jobs;
  • ambientes dev, staging e prod;
  • desenvolvedores testando agentes ou automações;
  • necessidade de calcular margem por cliente.

O painel nativo mostra totais diários, modelo e limite de uso. Ele não fornece atribuição por funcionalidade, rota HTTP, cliente ou job interno. A API de uso do OpenAI também retorna dados agregados, não eventos por requisição.

Para contexto de precificação, veja a análise de preços do GPT-5.5. Para um problema parecido no lado de ferramentas de desenvolvedor, veja cobrança de uso do GitHub Copilot para equipes de API. A referência oficial da API está em OpenAI API Reference.

Modelo de dados para atribuição de custos

A unidade de análise deve ser um evento por requisição OpenAI.

Um esquema mínimo:

Coluna Tipo Exemplo Por que importa
request_id uuid 7a91... Idempotência, deduplicação e retentativas
timestamp timestamptz 2026-05-06T14:23:01Z Séries temporais e alertas
feature text support-chat Funcionalidade do produto
route text /api/v1/chat/answer Rota HTTP ou job
customer_id text cust_4291 Custo por cliente
environment text prod Separar produção de dev/staging
model text gpt-5.5 Precificação por modelo
prompt_tokens int 15234 Tokens de entrada
completion_tokens int 812 Tokens de saída
reasoning_tokens int 4500 Tokens de raciocínio cobrados como saída
cached_tokens int 12000 Tokens com cache de prompt
latency_ms int 2341 Correlação entre custo e UX
cost_usd numeric 0.045672 Custo calculado no momento da requisição
prompt_cache_key text system-v3 Análise de cache por prompt
error_code text 429 Diagnóstico de falhas e retentativas

Calcule o custo no momento da gravação, não apenas na consulta. Preços mudam; o evento deve refletir a tarifa aplicada no dia da chamada.

Exemplo em Python:

PRICING = {  # USD por 1M tokens, a partir de maio de 2026
    "gpt-5.5":      {"input": 5.00,  "cached": 2.50,  "output": 30.00},
    "gpt-5.5-pro":  {"input": 30.00, "cached": 15.00, "output": 180.00},
    "gpt-5.4":      {"input": 2.50,  "cached": 1.25,  "output": 15.00},
    "gpt-5.4-mini": {"input": 0.25,  "cached": 0.125, "output": 2.00},
}

def compute_cost_usd(
    model,
    prompt_tokens,
    cached_tokens,
    completion_tokens,
    reasoning_tokens
):
    rates = PRICING[model]

    uncached = max(0, prompt_tokens - cached_tokens)

    input_cost = (uncached * rates["input"]) / 1_000_000
    cache_cost = (cached_tokens * rates["cached"]) / 1_000_000
    output_cost = (
        (completion_tokens + reasoning_tokens) * rates["output"]
    ) / 1_000_000

    return round(input_cost + cache_cost + output_cost, 6)
Enter fullscreen mode Exit fullscreen mode

Tokens de raciocínio aparecem em usage.completion_tokens_details.reasoning_tokens, mas são cobrados como saída. Se você ignorar isso, subestimará o custo de chamadas com modo Thinking. Para a matemática completa, consulte a análise de preços do GPT-5.5.

Wrapper OpenAI com atribuição de custos

A regra prática: nenhuma funcionalidade deve chamar o SDK diretamente. Todas as chamadas passam por um wrapper.

import time
import uuid
import json
import logging
from openai import OpenAI

client = OpenAI()
logger = logging.getLogger("llm.cost")

def call_with_attribution(
    *,
    feature,
    route,
    customer_id,
    environment,
    model,
    messages,
    **openai_kwargs
):
    request_id = str(uuid.uuid4())
    started = time.time()
    error_code = None
    response = None

    try:
        response = client.chat.completions.create(
            model=model,
            messages=messages,
            **openai_kwargs
        )
        return response

    except Exception as e:
        error_code = getattr(e, "code", "unknown_error")
        raise

    finally:
        latency_ms = int((time.time() - started) * 1000)
        usage = response.usage if response else None

        prompt_tokens = getattr(usage, "prompt_tokens", 0)
        completion_tokens = getattr(usage, "completion_tokens", 0)

        cached_tokens = getattr(
            getattr(usage, "prompt_tokens_details", None),
            "cached_tokens",
            0
        ) or 0

        reasoning_tokens = getattr(
            getattr(usage, "completion_tokens_details", None),
            "reasoning_tokens",
            0
        ) or 0

        cost_usd = compute_cost_usd(
            model,
            prompt_tokens,
            cached_tokens,
            completion_tokens,
            reasoning_tokens
        )

        logger.info(json.dumps({
            "event": "openai.request",
            "request_id": request_id,
            "feature": feature,
            "route": route,
            "customer_id": customer_id,
            "environment": environment,
            "model": model,
            "prompt_tokens": prompt_tokens,
            "completion_tokens": completion_tokens,
            "reasoning_tokens": reasoning_tokens,
            "cached_tokens": cached_tokens,
            "latency_ms": latency_ms,
            "cost_usd": cost_usd,
            "error_code": error_code,
        }))
Enter fullscreen mode Exit fullscreen mode

Uso:

response = call_with_attribution(
    feature="support-chat",
    route="/api/v1/chat/answer",
    customer_id="cust_4291",
    environment="prod",
    model="gpt-5.5",
    messages=[
        {"role": "system", "content": "Você é um assistente de suporte."},
        {"role": "user", "content": "Como redefino minha senha?"}
    ]
)
Enter fullscreen mode Exit fullscreen mode

Esse wrapper vira a superfície única de governança. A partir dele, envie os logs para BigQuery, ClickHouse, Snowflake, Postgres ou qualquer pipeline existente com Vector, Fluent Bit, Logstash ou coletor OTLP.

Em Node.js, o padrão é o mesmo:

  1. receba metadados obrigatórios;
  2. chame o SDK;
  3. leia response.usage;
  4. calcule o custo;
  5. emita um JSON por requisição.

Consultas úteis no data warehouse

Depois que os eventos chegam ao warehouse, a atribuição vira SQL.

Gasto diário por funcionalidade

SELECT
  feature,
  DATE_TRUNC(timestamp, DAY) AS day,
  COUNT(*) AS requests,
  SUM(cost_usd) AS spend_usd,
  SUM(prompt_tokens + completion_tokens + reasoning_tokens) AS total_tokens,
  AVG(latency_ms) AS avg_latency_ms,
  SUM(cached_tokens) / NULLIF(SUM(prompt_tokens), 0) AS cache_hit_rate
FROM openai_events
WHERE environment = 'prod'
  AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
GROUP BY feature, day
ORDER BY day DESC, spend_usd DESC;
Enter fullscreen mode Exit fullscreen mode

Top clientes por gasto no mês

SELECT
  customer_id,
  COUNT(*) AS requests,
  SUM(cost_usd) AS spend_usd,
  AVG(cost_usd) AS avg_cost_per_request
FROM openai_events
WHERE environment = 'prod'
  AND timestamp >= DATE_TRUNC(CURRENT_TIMESTAMP(), MONTH)
GROUP BY customer_id
ORDER BY spend_usd DESC
LIMIT 20;
Enter fullscreen mode Exit fullscreen mode

Rotas que mais gastaram ontem

SELECT
  route,
  feature,
  COUNT(*) AS requests,
  SUM(cost_usd) AS spend_usd
FROM openai_events
WHERE environment = 'prod'
  AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY)
GROUP BY route, feature
ORDER BY spend_usd DESC
LIMIT 20;
Enter fullscreen mode Exit fullscreen mode

Como validar o wrapper com Apidog

Antes de confiar nos dashboards, valide o fluxo de ponta a ponta. Um campo errado no log pode gerar atribuição silenciosamente incorreta.

Use o Apidog para criar cenários que executam seus endpoints de IA e verificam se os metadados chegam corretamente.

Checklist:

  1. Crie uma requisição para seu endpoint de IA.
  2. Envie customer_id, feature e demais dados esperados.
  3. Execute a chamada em staging.
  4. Capture a resposta e o evento de log.
  5. Verifique se o log contém:
    • feature;
    • route;
    • customer_id;
    • environment;
    • model;
    • prompt_tokens > 0;
    • cost_usd > 0;
    • request_id.
  6. Reexecute o cenário e valide o comportamento de retentativas.
  7. Rode o mesmo cenário em produção usando variáveis de ambiente do Apidog.

Exemplo de payload esperado no log:

{
  "event": "openai.request",
  "request_id": "7a91f5c8-7a1e-4c7a-83e0-df56b6b5b111",
  "feature": "support-chat",
  "route": "/api/v1/chat/answer",
  "customer_id": "cust_4291",
  "environment": "staging",
  "model": "gpt-5.5",
  "prompt_tokens": 1234,
  "completion_tokens": 210,
  "reasoning_tokens": 0,
  "cached_tokens": 800,
  "latency_ms": 1820,
  "cost_usd": 0.00834,
  "error_code": null
}
Enter fullscreen mode Exit fullscreen mode

Para ampliar esse fluxo, veja ferramentas de teste de API para engenheiros de QA e desenvolvimento de API contract-first.

Limites e alertas

A atribuição só fica operacional quando você adiciona limites.

1. Use chaves por ambiente ou funcionalidade

Exemplos:

  • prod-support-chat
  • prod-summarization
  • prod-rag-search
  • staging-all
  • dev-sandbox

Isso permite aplicar limites no painel do OpenAI e reduzir o impacto de loops descontrolados.

2. Crie alertas por desvio

Exemplo: alertar quando uma funcionalidade gastar 3x mais que sua média horária dos últimos 7 dias.

WITH hourly AS (
  SELECT
    feature,
    TIMESTAMP_TRUNC(timestamp, HOUR) AS hour,
    SUM(cost_usd) AS spend_usd
  FROM openai_events
  WHERE environment = 'prod'
    AND timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  GROUP BY feature, hour
),

baseline AS (
  SELECT
    feature,
    AVG(spend_usd) AS avg_hourly_spend
  FROM hourly
  WHERE hour < TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), HOUR)
  GROUP BY feature
),

current_hour AS (
  SELECT
    feature,
    SUM(cost_usd) AS current_spend
  FROM openai_events
  WHERE environment = 'prod'
    AND timestamp >= TIMESTAMP_TRUNC(CURRENT_TIMESTAMP(), HOUR)
  GROUP BY feature
)

SELECT
  c.feature,
  c.current_spend,
  b.avg_hourly_spend
FROM current_hour c
JOIN baseline b USING (feature)
WHERE c.current_spend > b.avg_hourly_spend * 3;
Enter fullscreen mode Exit fullscreen mode

Envie o resultado para Slack, PagerDuty, Opsgenie ou outro canal de incidentes.

Otimizações práticas de custo

Cache de prompt

O GPT-5.5 cobra 50% da taxa de entrada para tokens em cache. Para melhorar a taxa de acerto:

  • mantenha o prompt de sistema estável;
  • coloque variáveis no fim do prompt;
  • evite alterar instruções globais sem necessidade;
  • monitore cache_hit_rate por funcionalidade.

A documentação oficial está em Prompt Caching.

API Batch para trabalho offline

Use Batch para cargas que não precisam de resposta síncrona:

  • sumarização noturna;
  • avaliações;
  • reprocessamento de documentos;
  • geração de embeddings;
  • rotinas de backfill.

Marque os eventos com batch_job_id para manter a atribuição.

Esforço de raciocínio

Se você usa modelos com configuração de raciocínio, audite o nível aplicado por funcionalidade.

Perguntas úteis:

  • medium é realmente necessário?
  • low passa nos critérios de qualidade?
  • qual é o custo por resposta aceita?
  • o ganho de qualidade justifica o aumento de tokens?

Para mais detalhes, veja como usar a API GPT-5.5.

Janela de contexto

Prompts longos são caros. Monitore:

  • média de prompt_tokens por funcionalidade;
  • crescimento semanal;
  • rotas com prompts fora do padrão;
  • requisições próximas do limite.

Se uma funcionalidade cresce em tokens sem mudança de produto, o prompt provavelmente está acumulando contexto desnecessário.

Limite de 272K tokens do GPT-5.5

O OpenAI aplica multiplicadores em requisições acima de 272K tokens: entrada 2x e saída 1.5x. Adicione um guardrail no wrapper:

if prompt_tokens > 250_000:
    logger.warning(json.dumps({
        "event": "openai.prompt_near_large_context_threshold",
        "request_id": request_id,
        "feature": feature,
        "route": route,
        "customer_id": customer_id,
        "prompt_tokens": prompt_tokens
    }))
Enter fullscreen mode Exit fullscreen mode

Veja os detalhes no post sobre precificação do GPT-5.5.

Erros comuns

Evite estes padrões:

  • contar tokens de raciocínio como entrada;
  • confiar no painel do OpenAI para alertas em tempo real;
  • deixar feature ou customer_id como null;
  • marcar apenas endpoints HTTP e esquecer workers, filas e cron jobs;
  • usar unknown como valor padrão silencioso;
  • amostrar logs de custo;
  • calcular custo apenas no dashboard, sem persistir cost_usd;
  • não deduplicar retentativas;
  • misturar ambientes dev, staging e prod na mesma análise.

Para jobs assíncronos, use rotas sintéticas:

cron:nightly-summarize
queue:document-classification
worker:embedding-backfill
webhook:ticket-created
Enter fullscreen mode Exit fullscreen mode

Alternativas e ferramentas

Abordagem O que faz bem Custo Quando usar
API de uso do OpenAI Nativa, sem configuração, precisa ao centavo Grátis Um projeto, uma funcionalidade, sem atribuição por cliente
Helicone Proxy drop-in, painéis, cache, custos por usuário Camada gratuita; pago a partir de $20/mês Você quer um painel rápido e aceita proxy no caminho
Langfuse Código aberto, self-hosted ou nuvem, traces + custo Self-host gratuito; nuvem a partir de $29/mês Você quer rastreamento e custo em uma ferramenta open source
LangSmith Integração com LangChain, avaliação + custo Pago a partir de $39/usuário/mês Você já usa LangChain
Data warehouse próprio Controle total e integração com sua stack Tempo de engenharia Cargas grandes, dimensões customizadas e requisitos de dados

Trade-offs:

  • Proxy adiciona um salto no caminho crítico.
  • Observabilidade self-hosted exige operação.
  • Data warehouse próprio exige consultas, alertas e manutenção.
  • API de uso nativa é simples, mas limitada para atribuição detalhada.

Leituras úteis:

Casos de uso

SaaS B2B com IA por cliente

Uma empresa de inteligência de vendas gasta $80.000/mês com OpenAI. Sem atribuição, esse número é apenas uma linha de custo.

Com customer_id, ela descobre que 12% dos clientes geram 71% do gasto. A partir disso, pode:

  • criar cotas por plano;
  • cobrar excedente;
  • limitar abuso;
  • medir margem por cliente;
  • ajustar preços com dados reais.

Ferramenta interna para desenvolvedores

Uma organização oferece um assistente GPT-5.5 interno para devs.

Ao usar customer_id = dev_email, a equipe de plataforma identifica que três pessoas geram 50% do gasto. Duas estão executando loops de agentes esquecidos. Uma está usando legitimamente para trabalho crítico.

Resultado: corte de desperdício e cota maior para o uso legítimo.

Previsão de custo de nova funcionalidade

Antes de lançar uma sumarização com IA, o time estima:

  • tokens médios de entrada;
  • tokens médios de saída;
  • chamadas por usuário ativo;
  • usuários ativos esperados;
  • custo por usuário/dia.

Com histórico por funcionalidade, a previsão deixa de ser chute e vira modelo financeiro.

Conclusão

O painel do OpenAI mostra quanto você gastou. Ele não mostra por que você gastou.

Para tratar IA como custo de produto, implemente:

  • wrapper obrigatório para chamadas OpenAI;
  • metadados por requisição;
  • cálculo de custo no momento da gravação;
  • logs estruturados;
  • agregação no data warehouse;
  • limites por chave/projeto;
  • alertas por anomalia;
  • testes de ponta a ponta com Apidog.

Checklist final:

  • Marque toda requisição com feature, route, customer_id e environment.
  • Calcule cost_usd no momento da chamada.
  • Registre uma linha JSON por requisição.
  • Não amostre eventos de custo.
  • Use chaves separadas por ambiente ou funcionalidade.
  • Crie alertas por gasto anômalo.
  • Audite prompts, cache e esforço de raciocínio regularmente.
  • Valide o wrapper com Apidog antes de confiar nos dashboards.

Baixe o Apidog e use-o para verificar seu wrapper de atribuição de custos de ponta a ponta: envie requisições marcadas, valide o payload de log e reproduza cenários em diferentes ambientes.

Para leitura relacionada, veja a análise de preços do GPT-5.5 e cobrança de uso do GitHub Copilot para equipes de API.

FAQ

Os tokens de raciocínio contam como entrada ou saída?

Saída. Eles aparecem em usage.completion_tokens_details.reasoning_tokens e devem ser somados a completion_tokens no cálculo de custo. Veja a análise de preços do GPT-5.5.

response.usage bate com o painel do OpenAI?

As contagens de tokens devem corresponder. Diferenças de custo geralmente vêm de tabelas de preço desatualizadas ou arredondamento.

Posso fazer atribuição apenas com chaves de projeto?

Parcialmente. Chaves de projeto ajudam a separar ambientes ou grandes áreas, mas não resolvem atribuição por funcionalidade, cliente ou rota. Para isso, use metadados no nível da aplicação.

Retentativas contam custo duas vezes?

Se a requisição falhar antes da execução do modelo, normalmente não há usage. Se uma chamada bem-sucedida for repetida pela aplicação, você pode contar duas vezes. Use request_id idempotente e deduplicação na gravação.

A API de uso do OpenAI é suficiente para alertas?

Não para tempo real. Ela tem atraso. Use seu próprio pipeline de eventos para alertas e a API de uso para reconciliação.

Devo amostrar logs?

Não. O volume é pequeno e a amostragem quebra a atribuição por cliente e rota.

Isso funciona para outros provedores de LLM?

Sim. Adicione uma coluna provider e uma tabela de preços por provedor. O wrapper muda; o modelo de dados e os dashboards continuam. Para comparação, veja precificação da API DeepSeek V4.

Isso também funciona para embeddings e geração de imagem?

Sim, mas a matemática muda. Embeddings geralmente são cobrados por token de entrada. Imagens são cobradas por imagem e resolução. Adicione uma coluna endpoint, como chat, embeddings ou image, e calcule o custo conforme o tipo de chamada.

Top comments (0)