Skip to main content
Os rate limits ficam em dois lugares, por dois motivos diferentes. Nos endpoints que um atacante alcança sem credencial — os que adivinham senhas, enumeram endereços ou mandam e-mail em nome de outra pessoa — eles são defesa, e contam por IP do cliente. O boot é adicionalmente contado por chave publicável. Na superfície de máquina, atrás de uma chave uk_sk_…, eles são um contrato de capacidade. É a única superfície cujo chamador é um programa, e não uma pessoa: ali a contagem é por chave e os números vão em headers em toda resposta — o seu cliente consegue se conter em vez de descobrir o limite batendo nele.

Ao ser limitado

429
Retry-After carrega a janela em segundos. Espere; tentar antes só consome a próxima janela. Na superfície de máquina a janela é de um minuto, então nunca passa de 60.

Os limites

Autenticação de staff

Convites

Plano de clientes

O limite por chave no boot existe porque a chave publicável é a fronteira de tenant por onde uma enxurrada chega: bots e tráfego de landing page criariam linhas de visitante para sempre.

A superfície do próprio contato

Por sessão, não por IP. Atrás do NAT de uma operadora um endereço é milhares de pessoas, então um balde por IP numa superfície autenticada limita uma multidão pelo que um deles fez — e a sessão é o que de fato gasta o trabalho. O /v1/contact/token é a razão de o número existir: cada chamada é um decrypt de chave e uma assinatura.

A superfície de máquina

Por chave, não por IP. O seu backend chama isso de um endereço de datacenter que todos os seus servidores compartilham, e não carrega sessão — a chave é a única coisa que identifica o chamador, e a única sobre a qual você pode agir. Duas consequências que valem planejamento:
  • A sua própria segmentação é o seu isolamento. Uma chave por serviço — o app, o worker, o job noturno — significa que um backfill rodando a todo vapor não consegue limitar o seu caminho de login: os 1000 dele param antes de ter gasto mais de um terço dos 3000 compartilhados. Uma chave para tudo é um balde para tudo.
  • Criar chaves não compra cota. O teto do ambiente é o que faz o limite por chave significar algo: a quarta chave divide os mesmos 3000.
Live e test nunca dividem um teto, porque o contador é do ambiente. Um job de staging que gasta a cota inteira não consegue desacelerar a produção. Um retry respondido pela tabela de idempotência conta como qualquer outra requisição. Isso é deliberado: um replay ainda é uma ida e volta, e um cliente travado num laço de redelivery é exatamente o chamador que um limite precisa conseguir alcançar.
As demais rotas autenticadas — a sessão do painel — não têm throttle além dos endpoints de login acima. A credencial é o portão, e ela é revogável.

Lendo os headers

Toda resposta da superfície de máquina carrega o estado atual, tanto num 200 quanto num 429.
As duas famílias carregam os mesmos fatos, porque não existe uma convenção única: os nomes RateLimit-* são os do draft da IETF, e os X-RateLimit-* são os que a maioria dos clientes escritos na última década já lê. Use o que o seu cliente HTTP entender e ignore o outro. O único ponto em que elas divergem é o reset, e não é descuido — cada nome significa o que a sua própria convenção diz. RateLimit-Reset é quantos segundos esperar; X-RateLimit-Reset é o timestamp até o qual esperar. X-RateLimit-Scope existe porque há dois tetos em jogo e os números descrevem aquele que está mais perto de acabar. RateLimit-Limit: 3000 numa chave cujo limite próprio é 1000 quer dizer que o teto do ambiente é o que está pesando: outra chave sua está gastando a cota compartilhada.

Falhar aberto, falhar fechado

Duas posturas, escolhidas por endpoint. Os contadores vivem num store compartilhado por todas as instâncias da API. Quando esse store não pode ser alcançado, cada instância passa a contar sozinha — os limites continuam existindo e ficam mais frouxos, em vez de sumirem. Isso é deliberado, e é o único lugar onde esta plataforma não degrada graciosamente. Todo o resto que é opcional se desliga sem a sua dependência; um cadastro público atrás de limitador nenhum é a postura de segurança inteira desligada em silêncio, exatamente no momento em que um atacante é a explicação mais provável. O que você pode notar enquanto durar: um limite permitindo, por pouco tempo, um pouco mais que o número acima, porque várias instâncias estão contando até ele cada uma. Nada responde diferente, e não há nada para tratar. O RateLimit-Remaining passa a ser o resto daquela instância, e não o da frota inteira, então ele fica um pouco generoso. Os headers continuam vindo em vez de desaparecer enquanto isso durar — um contrato que some quando uma dependência some é um contrato no qual nenhum cliente pode se apoiar.

Ficando abaixo deles

1

Leia os headers na superfície de máquina

O RateLimit-Remaining da resposta que você já tem é mais barato que um 429. Um job em lote que pausa quando cai abaixo de uma margem nunca esbarra em nada.
2

Faça retry em 429, com backoff

Respeite Retry-After quando ele vier; use backoff exponencial quando não vier.
3

Não faça retry de um 4xx que não seja 429

Um 400 ou um 403 vai responder igual todas as vezes.
4

Faça debounce do boot

Um boot por carregamento de página, não um por componente que queira o contato.
5

Limite os seus próprios botões de reenvio

Reenvios de verificação e de magic link são 5 por hora. Um botão sem cooldown queima isso em segundos e o usuário só vê falha.