Teto de gasto diário em uma API de verificação: avisar antes de cortar

GuiaUNIFOKALAtualizado em 7 min de leituraProduto e integração
Ver em Markdown

Um orçamento por dia protege a conta de um flow mal configurado e de uma chave vazada. Como funciona o teto por organização e por chave, o aviso em 80% e o 429 com Retry-After.

Toda API cobrada por chamada tem o mesmo modo de falha silencioso: um flow configurado errado, um laço de retentativa sem limite ou uma chave que vazou transformam uma noite em uma fatura. O controle de custo por volume de requisições, o rate limit, não resolve isso, porque cem chamadas baratas e cem chamadas caras contam igual. O que resolve é um teto em dinheiro, por dia, configurado por quem paga a conta, que avisa antes de morder e só corta quando o dono da conta decidiu que deveria cortar.

Este artigo descreve como o orçamento diário de gasto do painel da UNIFOKAL funciona, quais decisões de desenho o sustentam e como a sua integração deve tratar a recusa.

Por que o teto é do cliente, e não nosso

Há duas grandezas diferentes com o mesmo nome. Uma é o nosso custo com fornecedores pagos: quando um módulo consulta uma base externa, esse custo é nosso e é controlado por um teto nosso, que quando estoura deixa o módulo em estado deferido, honesto e re-enriquecível, sem recusar a chamada do cliente. A outra é o gasto do cliente com a UNIFOKAL. O orçamento diário é sobre a segunda, e quem o configura é o proprietário da conta.

A diferença muda a resposta certa quando o teto chega. Estourar o nosso teto de fornecedor não é motivo para recusar a chamada de ninguém; estourar o orçamento que o próprio cliente definiu é. A única resposta honesta a "gaste no máximo X por dia" é recusar a chamada X+1, com o nome do motivo e a hora em que o orçamento volta. Deferir em silêncio seria gastar depois do teto.

Como o orçamento é composto

O orçamento vale por ambiente de produção, já que o sandbox não fatura, e tem duas camadas: a da organização, que vale para todas as chaves, e a de cada chave, que só aperta a da organização. O teto efetivo é o menor entre as camadas configuradas; uma camada ausente simplesmente não participa. Um teto de chave nunca afrouxa o da organização, e é assim que uma chave usada por um parceiro ou por um ambiente de teste interno pode ter um limite próprio, menor, sem que ninguém precise confiar que o parceiro vai se conter.

O gasto por chave conta as operações em que a chave é o ator no momento do gasto. A decisão da verificação acontece depois, num processo assíncrono, e é atribuída à organização e ao ambiente. A tela diz isso em uma frase, porque um contador por chave que fingisse cobrir o que não cobre seria pior do que nenhum.

Aviso em 80%, uma vez por dia, decidido no mesmo lugar do gasto

O orçamento avisa ao passar de 80% do teto. O detalhe que importa é onde o aviso é decidido. O jeito ingênuo é ler o contador depois de cada gasto e comparar com o teto. Com duas instâncias do serviço chegando ao mesmo ponto no mesmo milissegundo, cada uma lê 79% antes e 81% depois, e o cliente recebe dois avisos do mesmo dia, ou nenhum, porque as duas leram 79%.

A UNIFOKAL decide o aviso dentro da mesma atualização atômica que contabiliza o gasto, com a linha do contador travada: quem grava o patamar novo é quem emite o aviso, e a instância seguinte já lê o patamar gravado. Um aviso por dia, por contador, sem corrida. O mesmo travamento é o que garante que dez chamadas simultâneas contra um orçamento que só cabe três deixam passar exatamente três, e isso é provado por um teste de concorrência, não por inspeção do código.

Descer vale na hora; subir vale amanhã

O molde vem de uma frase que já valia para outro teto da plataforma: um teto que uma rota consegue subir não é um teto. Se o proprietário pode aumentar o orçamento com um clique, uma sessão de painel roubada também pode, e o orçamento deixa de proteger contra exatamente o cenário para o qual ele existe.

A conciliação entre "o dono opera o teto" e "o teto protege contra sessão roubada" não é fechar a porta: é assimetria de prazo. Diminuir o orçamento vale na hora. Aumentar, ou desligar, é agendado para a virada do dia, às 00:00 UTC. A tela mostra o agendamento pendente, quem o pediu e quando, e o registro de requisições guarda a chamada. Um atacante com a sessão do painel consegue, no máximo, agendar um aumento para amanhã, com um dia inteiro de janela para o dono desfazer. Além do prazo, a escrita exige o papel de proprietário e o código do aplicativo autenticador.

O teto nasce desligado. Quem nunca configurou nada continua exatamente como estava, e ligar é um ato explícito de quem paga a conta. Zero suspende o escopo: nenhuma sessão nova é admitida até o teto subir, e subir vale no dia seguinte.

O que a sua integração recebe

Quando o orçamento do dia acaba, a criação de sessão responde 429 Too Many Requests com o código estável spend_cap_reached e o cabeçalho Retry-After em segundos até a virada do dia. O status 429 é definido na RFC 6585 para o caso em que o cliente excedeu um limite estabelecido pelo servidor, e a RFC 9110 define o Retry-After como a indicação de quanto tempo o cliente deve esperar antes de repetir a requisição. Nada é cobrado na recusa.

Trate a recusa como pausa, não como retentativa. Um laço que insiste contra um 429 sem ler o Retry-After é exatamente o tráfego que o teto existe para conter, e o guia de segurança de APIs da OWASP lista o consumo de recurso sem restrição entre os dez riscos principais e o classifica como de prevalência ampla. A recomendação prática: ao receber spend_cap_reached, registre o evento, pause a fila de criação de sessões pelo prazo do cabeçalho e avise quem opera. Se o teto está baixo demais para a operação do dia, o proprietário sobe no painel, e a subida vale na virada. Se a pausa é inaceitável para o seu produto, a decisão certa é revisar o orçamento antes do incidente, não desligá-lo depois.

Já explicamos como tratar retentativas e idempotência na criação de sessão. O teto de gasto se apoia nas duas: a chamada recusada não consome idempotência, e a mesma chamada, repetida depois da virada com a mesma referência, é admitida normalmente.

Perguntas frequentes

O orçamento vale para o sandbox?

Não. O sandbox não fatura, então não há gasto a limitar. A tela do orçamento diz isso quando o ambiente ativo é o sandbox.

O que acontece com uma verificação que já estava em andamento quando o teto chegou?

Nada muda para ela. O teto é avaliado na criação de sessão, que é a porta onde o gasto é comprometido. Uma sessão já admitida segue a jornada até a decisão.

O aviso de 80% chega por qual canal?

O aviso é registrado no serviço e aparece na tela do orçamento, com o gasto do dia e o patamar cruzado. O canal de notificação ao cliente, por e-mail ou por evento de webhook, é uma decisão em aberto e será anunciado no changelog quando entrar.

Fontes citadas

  • RFC 6585, Additional HTTP Status Codes, seção 4, 429 Too Many Requests. IETF. https://www.rfc-editor.org/rfc/rfc6585
  • RFC 9110, HTTP Semantics, seção 10.2.3, Retry-After. IETF. https://www.rfc-editor.org/rfc/rfc9110
  • OWASP API Security Top 10 (2023), API4:2023 Unrestricted Resource Consumption. OWASP Foundation. https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/
  • Documentação do painel de operação da UNIFOKAL: o orçamento diário e o erro spend_cap_reached.