# Idempotência e rate limiting: chaves, 429, Retry-After, RateLimit

> O header Idempotency-Key (draft IETF) torna seguro um POST repetido: o servidor guarda o primeiro resultado por chave dentro de uma janela de desduplicação e reproduz-no em qualquer repetição, dando submissão exactly-once. O rate limiting protege o serviço: os pedidos acima do limite recebem 429 Too Many Requests com Retry-After, e os headers RateLimit anunciam a quota restante para que os clientes se autolimitem.

- URL canônico: https://www.broadnet.me/pt/reference/idempotency-and-rate-limiting
- Idioma: pt
- Última atualização: 2026-07-19
- Editor: BroadNet (https://www.broadnet.me)

Dois padrões HTTP standards-track para clientes seguros e bem-comportados: o header Idempotency-Key (draft IETF) para submissão exactly-once com uma janela de desduplicação e replay da resposta, e rate limiting — 429 com Retry-After, os headers RateLimit / RateLimit-Policy (draft IETF), token buckets e backpressure do cliente.

## O header Idempotency-Key

A submissão de mensagens é um POST, que não é idempotente, mas as redes obrigam os clientes a repetir quando uma resposta se perde — criando o clássico envio duplicado. O draft Idempotency-Key do grupo de trabalho HTTP-API da IETF normaliza a solução: o cliente gera uma chave única (um UUID) por operação lógica e envia-a no header de pedido Idempotency-Key. O servidor regista a chave com o desfecho do primeiro pedido e, se voltar a ver a mesma chave, não executa uma segunda vez — devolve o resultado guardado. Assim, um retry após um timeout é garantidamente inócuo: ou a primeira tentativa nunca chegou (e esta executa) ou chegou (e o seu resultado é reproduzido). A chave pertence à operação, não à ligação, pelo que o cliente reutiliza a mesma chave em cada retry desse mesmo envio.

*POST idempotente com uma chave gerada pelo cliente*

```http
# Generic IETF-draft example (not the BroadNet API, which takes no
# Idempotency-Key header: see /developers/idempotency)
POST /v1/messages HTTP/1.1
Host: api.example
Idempotency-Key: 8f14e45f-ea7b-4c0f-9b2a-1d2c3e4f5a6b
Content-Type: application/json

{ "to": "+15551234567", "text": "..." }

# first call  -> 202 Accepted, id 01HZY8Q3M6   (executed, stored)
# same key    -> 202 Accepted, id 01HZY8Q3M6   (replayed, not re-sent)
```

## Janela de desduplicação, replay da resposta e conflitos

Uma chave de idempotência não é lembrada para sempre; o servidor guarda-a durante uma janela de desduplicação (habitualmente 24 horas) o suficiente para cobrir qualquer retry realista e depois expira-a. Dentro dessa janela, uma repetição da chave reproduz o status code e o corpo guardados textualmente — o mesmo 202 e o mesmo message id — para que o cliente veja exatamente o que teria visto se a primeira resposta tivesse chegado. Dois casos-limite precisam de tratamento explícito. Se uma chave for reutilizada com um corpo de pedido diferente, isso é um bug do cliente e o servidor devolve 409 Conflict em vez de enviar em silêncio a coisa errada. Se um retry chegar enquanto o primeiro pedido ainda está em curso, o servidor devolve um conflito ou 'in progress' em vez de iniciar uma segunda execução, para que a concorrência não derrote a garantia.

*Desfechos do Idempotency-Key*

| Situação | Comportamento do servidor | Status |
|---|---|---|
| Nova chave | Executar, armazenar chave + resultado | Normal (ex: 202) |
| Mesma chave, mesmo corpo | Reenviar a resposta armazenada, não executar novamente | Status original |
| Mesma chave, corpo diferente | Rejeitar — chave vinculada ao primeiro payload | 409 Conflict |
| Repetição enquanto a primeira ainda está em andamento | Não inicie uma segunda execução | 409 / em andamento |
| Chave expirada (fora da janela) | Tratado como novo | Normal |

## Rate limiting e 429

Uma plataforma de mensagens partilhada protege-se a si e aos outros tenants limitando a rapidez com que qualquer cliente pode chamar, e sinaliza uma violação com um status específico. As RFC 9110 e RFC 6585 definem 429 Too Many Requests exatamente para isto: o cliente enviou pedidos a mais num dado intervalo de tempo. Um servidor bem-comportado emparelha o 429 com um header Retry-After que diz ao cliente quanto esperar antes de tentar de novo (seja um atraso em segundos, seja uma data HTTP). A obrigação do cliente é honrá-lo — parar, esperar o intervalo indicado e depois retomar — em vez de repetir de imediato, o que só aprofunda a sobrecarga. Um 429 é transitório e seguro de repetir, ao contrário de um 4xx que indica um pedido malformado.

*429 com headers Retry-After e RateLimit*

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 2
RateLimit: limit=100, remaining=0, reset=2
RateLimit-Policy: 100;w=1
Content-Type: application/problem+json

{ "type": "https://example/problems/rate-limited",
  "title": "Too Many Requests", "status": 429 }
```

## Headers RateLimit e RateLimit-Policy

Reagir a um 429 depois do facto é um desperdício; o draft RateLimit-headers da IETF permite a um cliente ver o seu orçamento antes de o exceder. Nas respostas comuns, o servidor anuncia a quota atual com um header RateLimit que transporta o limite, a permissão restante e os segundos até o reset da janela, e um header RateLimit-Policy que descreve a própria política (por exemplo 100 pedidos por janela de 1 segundo). Um cliente que os leia pode regular-se — abrandando à medida que remaining se aproxima de zero — e nunca disparar um 429. Isto transforma o rate limiting de uma rejeição punitiva a posteriori num sinal cooperativo, que é todo o propósito de normalizar os nomes dos headers para que qualquer biblioteca de cliente os possa consumir.

*Headers padrão de sinalização de rate limit*

| Cabeçalho | Transporta | Exemplo |
|---|---|---|
| 429 Too Many Requests | O status de limite excedido | linha de status |
| Retry-After | Quanto tempo esperar antes de tentar novamente | Retry-After: 2 |
| RateLimit | limite / restante / reset para a janela | limit=100, remaining=17, reset=1 |
| RateLimit-Policy | A política de quotas em vigor | 100;w=1 (100 per 1s) |

## Token bucket e como os limites são impostos

O algoritmo token-bucket é o mecanismo habitual por trás destes headers porque limita a taxa sustentada tolerando ao mesmo tempo bursts curtos. Um bucket contém até um número fixo de tokens e reabastece a um ritmo estável; cada pedido remove um token, e um pedido que encontre o bucket vazio é rejeitado com 429. O tamanho do bucket define o burst que um cliente pode gastar de uma vez e o ritmo de reabastecimento define o teto de longo prazo, pelo que um cliente pode enviar um burst rápido após um período inativo mas não pode exceder a média. O valor remaining do RateLimit é efetivamente a contagem de tokens, e reset é quando o bucket estará reabastecido — que é exatamente a informação de que um cliente regulado precisa. Este controlo de fluxo na camada HTTP é o análogo REST do dimensionamento de janela SMPP e do throttling por enquire_link na sessão binária.

## Backpressure do cliente

A metade do cliente do bom comportamento de rate limit é a backpressure: moldar a carga de saída para que fique dentro do orçamento anunciado em vez de disparar tudo e absorver 429s. Na prática, isso significa um limitador do lado do cliente (um token bucket a espelhar o do servidor), ler os headers RateLimit para ajustar o ritmo e, num 429, recuar durante o intervalo Retry-After com jitter antes de retomar. Para um envio em massa, significa medir as submissões ao teto sustentado em vez de as despejar, para que a plataforma se mantenha saudável e a própria latência do cliente se mantenha previsível. A BroadNet documenta o seu comportamento concreto de idempotência e rate limit para programadores.

## Perguntas frequentes

### O que faz o header Idempotency-Key?

Torna seguro um POST repetido. O cliente envia uma chave única por operação lógica; o servidor executa o primeiro pedido com essa chave e guarda o resultado, reproduzindo depois o resultado guardado em qualquer repetição da mesma chave dentro de uma janela de desduplicação. Assim, um retry após uma resposta perdida ou executa uma vez ou reproduz — nunca envia em duplicado. Está especificado num draft do grupo de trabalho HTTP-API da IETF.

### Durante quanto tempo o servidor lembra uma chave de idempotência?

Durante uma janela de desduplicação — habitualmente cerca de 24 horas — o suficiente para cobrir qualquer retry realista, após o que a chave expira e uma reutilização é tratada como nova. Dentro da janela, uma repetição da chave reproduz o status code e o corpo originais textualmente em vez de reexecutar.

### O que acontece se reutilizar uma chave de idempotência com um corpo diferente?

O servidor rejeita-a com 409 Conflict. A chave está ligada ao payload do primeiro pedido, pelo que reutilizá-la com um corpo diferente é tratado como um erro de cliente em vez de enviar em silêncio a mensagem errada. Reutilize a mesma chave apenas para retries da operação idêntica.

### O que deve um cliente fazer quando recebe um 429?

Parar e honrar o header Retry-After — esperar os segundos indicados (ou até à data dada) e depois retomar — em vez de repetir de imediato, o que só aprofunda a sobrecarga. Um 429 é transitório e seguro de repetir depois de decorrida a espera, idealmente com algum jitter para que muitos clientes não retomem em sincronia.

### Para que servem os headers RateLimit e RateLimit-Policy?

Permitem a um cliente ver a sua quota antes de a exceder. O RateLimit transporta o limite, a permissão restante e o tempo de reset da janela atual; o RateLimit-Policy descreve a política (por exemplo 100 pedidos por segundo). Um cliente que os leia pode regular-se e evitar disparar um 429. Ambos estão definidos num draft da IETF.

### Como se relaciona um token bucket com os headers RateLimit?

O token bucket é o mecanismo de imposição: um bucket de tamanho fixo reabastece a um ritmo estável, cada pedido gasta um token, e um bucket vazio dá um 429. O valor remaining do RateLimit é essencialmente a contagem atual de tokens e reset é quando o bucket reabastece — pelo que um cliente que leia esses headers sabe exatamente quanto burst e taxa sustentada lhe restam.

## Fontes

- [IETF draft — Idempotency-Key HTTP Header Field](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-idempotency-key-header)
- [IETF draft — RateLimit header fields for HTTP](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers)

## Relacionados

- [Design de API REST de mensagens](https://www.broadnet.me/pt/reference/rest-messaging-api-design)
- [Entrega e fiabilidade de webhooks](https://www.broadnet.me/pt/reference/webhook-delivery-and-reliability)
- [SMPP enquire_link e throttling](https://www.broadnet.me/pt/reference/smpp-enquire-link-throttling)
- [Guia de idempotência da BroadNet](https://www.broadnet.me/developers/idempotency)
- [Limites de taxa da BroadNet](https://www.broadnet.me/pt/developers/rate-limits)
