Limite de taxa em API: o que devolver e como reagir
Os dois lados do rate limit: que RFC define o 429, o que precisa vir no cabeçalho para o cliente saber quando voltar, e como fazer retry com recuo exponencial e aleatorização.
Foto: Chris Ried, Unsplash
Toda API séria tem limite de taxa. A parte que quase ninguém escreve é o contrato de como o limite se comunica: quando o servidor diz "chega", o cliente precisa saber se o problema é dele ou do serviço, quanto tempo esperar e se aquela requisição específica pode ser repetida sem estragar nada.
Quando esse contrato falta, os dois lados perdem. O servidor devolve um erro mudo, o cliente repete na hora e o que era controle de carga vira amplificador: a mesma requisição rejeitada volta dez vezes por segundo, consumindo conexão, log e CPU justamente quando o serviço tinha menos folga.
Este texto é para quem está dos dois lados, o que costuma ser o caso de quem integra verificação de identidade: você consome a API de um fornecedor e expõe a sua. Cada lado tem um padrão.
429 não é 503, e a diferença decide o que o cliente faz
O código 429 Too Many Requests não está na especificação principal do HTTP. Ele é definido pela RFC 6585, Additional HTTP Status Codes, de Mark Nottingham e Roy Fielding, publicada em abril de 2012, e continua vigente: a RFC 9110, HTTP Semantics, especificação atual da semântica do protocolo, lista como obsoletas várias RFC de HTTP, entre elas a 2818, a 7231 e a 7235, mas não a 6585, que ela cita como a extensão que definiu códigos para limite de taxa.
O texto da 6585 é curto: o 429 indica que o usuário enviou requisições demais num dado intervalo, a resposta deveria explicar a condição e pode trazer um cabeçalho Retry-After. A mesma RFC avisa que não define como o servidor identifica o usuário nem como conta as requisições: isso é decisão de cada serviço.
Já o 503 Service Unavailable está na RFC 9110, seção 15.6.4, e significa outra coisa: o servidor está temporariamente incapaz de atender por sobrecarga ou manutenção programada, e a condição provavelmente passa depois de algum tempo.
A diferença não é cosmética. O 429 é sobre aquele cliente: os outros seguem sendo atendidos, o limite é individual e volta sozinho. O 503 é sobre o serviço, e o tempo de retorno depende de uma recuperação, não de um relógio de cota. Quem trata os dois como o mesmo erro espera de menos numa situação e de mais na outra, e alerta a equipe errada quando o painel acende. Separá-los no monitoramento da integração distingue "estou batendo na minha cota" de "o fornecedor caiu".
Do lado de quem serve: dizer quando voltar
Devolver 429 sem dizer quando voltar empurra o cliente para o pior comportamento possível: sem informação, a implementação típica tenta de novo imediatamente. Três campos resolvem.
Retry-After. Definido na RFC 9110, seção 10.2.3. O valor é uma data HTTP ou um número de segundos, inteiro decimal não negativo: o próprio exemplo da RFC usa Retry-After igual a 120 para pedir dois minutos de espera. Em API entre máquinas o formato em segundos costuma ser melhor, porque não depende de o relógio nem o fuso do cliente estarem certos.
RateLimit-Policy e RateLimit. Existe um trabalho de padronização em curso no IETF, o rascunho RateLimit header fields for HTTP, do grupo de trabalho HTTPAPI. Atenção ao status: na versão 11, de 23 de maio de 2026, ele ainda é um Internet-Draft ativo, não uma RFC publicada.
Os nomes exatos dos campos, conforme o rascunho: RateLimit-Policy anuncia a política de cota, com os parâmetros q (a cota, obrigatório), qu (a unidade), w (a janela de tempo) e pk (a chave de partição). RateLimit anuncia o estado atual, com r (cota disponível, obrigatório), t (janela efetiva) e pk. O próprio documento exemplifica duas políticas na mesma resposta: uma de rajada, de 100 unidades por minuto, e uma diária, de 1000.
O rascunho também define a regra de conflito: se a resposta trouxer RateLimit e Retry-After juntos, o Retry-After tem precedência.
Um corpo de erro legível por máquina. A RFC 9457, Problem Details for HTTP APIs, de julho de 2023, define esse formato e obsoleta explicitamente a RFC 7807. O rascunho de RateLimit registra tipos de problema prontos: quota-exceeded e abnormal-usage-detected, ambos com status recomendado 429, e temporary-reduced-capacity, com 503, todos com um membro violated-policies listando as políticas estouradas. É a diferença entre o cliente ler "429" e saber que estourou a cota diária e não a de rajada.
Do lado de quem consome: recuar com aleatorização
O padrão do lado do cliente é o recuo exponencial: em vez de repetir na mesma hora, espere um intervalo base e dobre esse intervalo a cada nova falha. Se o servidor mandou Retry-After, o valor dele vence o seu cálculo.
A aleatorização não é enfeite. O próprio rascunho do IETF trata disso na seção sobre exaustão de recurso: ao devolver uma janela efetiva, o servidor precisa saber que muitos clientes limitados podem voltar exatamente no instante indicado, e o mesmo vale para o Retry-After. O exemplo do documento é uma cota que zera às 18:00:00, com alta probabilidade de todos os clientes aparecerem às 18:00:00. Esse é o rebanho trovejante: o pico de retorno fica pior que o original porque as chegadas passam a estar sincronizadas por um relógio comum. O rascunho aponta a cura: somar alguma aleatorização à janela.
Na prática, o cliente sorteia a espera dentro de uma faixa em torno do valor calculado, e o servidor varia um pouco o Retry-After que devolve a cada cliente.
Faltam dois limites. Um teto de tentativas, porque repetir para sempre transforma falha em vazamento de recurso: a tentativa número quarenta não vai dar certo e ainda ocupa memória e conexão. E um teto de espera, para que a exponencial não produza meia hora de espera em algo que o usuário está olhando. Passado o teto, desista com erro claro e registre, em vez de insistir em silêncio.
O que não se deve repetir
A RFC 9110 é direta na seção 9.2.2: um cliente não deveria repetir automaticamente uma requisição com método não idempotente, a menos que tenha como saber que a semântica é de fato idempotente ou como detectar que a original nunca foi aplicada. Um proxy não pode fazer isso de jeito nenhum, e ninguém deveria repetir automaticamente uma tentativa automática que já falhou.
É por isso que o retry e a chave de idempotência são o mesmo assunto. Um POST que cria uma verificação cobrada não é idempotente por natureza: repetir pode cobrar duas vezes. Com uma chave de idempotência, ele passa a ser, e o retry automático deixa de ser aposta. Sem a chave, a regra honesta é não repetir automaticamente o que escreve.
Falta separar o erro que vale repetir do que não vale. Vale repetir o transitório: 429, 503, 504, falha de conexão e timeout de rede, porque a condição muda sozinha com o tempo. Não vale repetir o erro de requisição: 400, 401, 403, 404 e 422 descrevem algo errado no que você mandou ou em quem você é, e a centésima tentativa manda exatamente a mesma coisa errada.
Um detalhe fácil de esquecer: a rajada de repetição depois de uma indisponibilidade é o segundo pico do dia, e acerta o seu receptor de webhook também. Inclua esse cenário no teste de carga e tenha um caminho de reconciliação para o que não chegou.
Na UNIFOKAL, por exemplo, o comportamento de erro é parte do contrato da API, escrito junto do resto do material de integração. Isso serve de critério ao avaliar fornecedor: se a documentação não diz o que ele devolve ao limitar você, a integração descobre em produção.
Perguntas frequentes
Devolvo 429 ou 503 quando estou sem capacidade?
Depende de quem causou. Se aquele cliente específico passou da cota dele, é 429. Se a capacidade caiu para todo mundo, por sobrecarga ou manutenção, é 503, que a RFC 9110 descreve exatamente assim. O rascunho de RateLimit reforça a separação ao registrar o tipo de problema temporary-reduced-capacity com status recomendado 503.
Posso tratar os cabeçalhos de RateLimit como padrão publicado?
Ainda não. Em maio de 2026 o rascunho de cabeçalhos RateLimit seguia como Internet-Draft ativo do grupo HTTPAPI, sem virar RFC. Implementar já é razoável, mas o documento pode mudar até a publicação. Documente o que a sua API emite em vez de dizer só "seguimos o padrão".
Fontes citadas
- RFC 6585, Additional HTTP Status Codes, IETF, abril de 2012, seção 4, que define o 429: rfc-editor.org
- RFC 9110, HTTP Semantics, IETF, seções 9.2.2 (métodos idempotentes e repetição automática), 10.2.3 (Retry-After) e 15.6.4 (503 Service Unavailable): rfc-editor.org
- RFC 9457, Problem Details for HTTP APIs, IETF, julho de 2023, que obsoleta a RFC 7807: rfc-editor.org
- RateLimit header fields for HTTP, rascunho draft-ietf-httpapi-ratelimit-headers-11, grupo de trabalho HTTPAPI do IETF, 23 de maio de 2026, Internet-Draft ativo: datatracker.ietf.org
