ZAP-API
PreçosCasos de UsoBlogDocsLogin
Começar grátis
  1. Blog
  2. Rate limiting em WhatsApp API: throttle inteligente por sessão
Arquitetura

Rate limiting em WhatsApp API: throttle inteligente por sessão

Implemente rate limiting inteligente para disparos WhatsApp: throttle dinâmico por número, janelas deslizantes e backoff automático para evitar banimento.

19 de maio de 2026·13 min de leitura·Equipe Editorial ZAP API

Banimento de número WhatsApp é o pior pesadelo de quem opera em escala. Você acorda, abre o painel e vê instância em "BANNED" — número queimado, contatos perdidos, histórico inacessível. Recuperação é difícil e frequentemente impossível. A boa notícia: 90% dos banimentos seguem padrões previsíveis e dá para evitar com rate limiting inteligente.

Este artigo mostra a estratégia completa de throttling: 2 camadas de limite (API REST + comportamental WhatsApp), token bucket distribuído em Redis, ajuste dinâmico baseado em taxa de erro, e o que fazer quando você manda número novo entrar em produção.

As 2 camadas de rate limit

Camada 1: API REST

É o limite da própria ZAP API por instância. Existe para proteger nossa infraestrutura e a sua. Hoje em dia: 60 requisições/minuto por instância, retorna 429 com headers padrão.

// Headers em toda resposta:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1715812230   // unix timestamp do reset

Estoura esse limite e você recebe 429 Too Many Requests com Retry-After: N em segundos. Backoff e tente de novo.

Camada 2: Comportamental WhatsApp

Esse é o limite que importa para banimento. Não é documentado pela WhatsApp, mas baseado em milhões de mensagens enviadas, sabemos:

  • Número novo (recém-conectado): não passe de 30 mensagens/hora na primeira semana, 100/hora na segunda, 300/hora a partir da terceira (warmup).
  • Número aquecido (3+ meses ativos): 1.000-2.000 msgs/hora seguro
  • Número antigo confiável (1+ ano): 5.000+ msgs/hora factível, mas evite explosões — distribua ao longo do dia
  • Janela de 24h: nunca passe de 30k msgs/dia em um único número
  • Mesma mensagem para muitos: reduzir score de "spam" — varie texto com spintax
  • Velocidade de envio: não menos que 800ms entre mensagens (evita parecer robô)

Token bucket por instância em Redis

O algoritmo clássico para rate limiting com burst controlado. Cada instância tem um "balde de tokens" — toma 1 token por mensagem, balde reabastece a uma taxa fixa. Se balde vazio, mensagem espera.

// rate-limiter.ts
import { createClient } from "redis";
import Redlock from "redlock";

const redis = createClient({ url: process.env.REDIS_URL });
await redis.connect();
const redlock = new Redlock([redis as any]);

interface BucketConfig {
  capacity: number;       // tokens máximos no balde (burst)
  refillPerSec: number;   // tokens repostos por segundo
}

export async function takeToken(instanceId: string, cfg: BucketConfig) {
  const key = `bucket:${instanceId}`;
  const lock = await redlock.acquire([`lock:${key}`], 2000);

  try {
    const now = Date.now() / 1000;
    const raw = await redis.get(key);
    const state = raw ? JSON.parse(raw) : { tokens: cfg.capacity, ts: now };

    // Reabastece com base no tempo decorrido
    const elapsed = now - state.ts;
    state.tokens = Math.min(cfg.capacity, state.tokens + elapsed * cfg.refillPerSec);
    state.ts = now;

    if (state.tokens < 1) {
      // Quanto falta para 1 token?
      const waitMs = Math.ceil((1 - state.tokens) / cfg.refillPerSec * 1000);
      await redis.set(key, JSON.stringify(state), { EX: 3600 });
      return { allowed: false, retryInMs: waitMs };
    }

    state.tokens -= 1;
    await redis.set(key, JSON.stringify(state), { EX: 3600 });
    return { allowed: true };
  } finally {
    await lock.release();
  }
}

// Uso (ex.: número aquecido, 1k msgs/hora = 0.27 tokens/seg):
const result = await takeToken("inst_xyz", { capacity: 60, refillPerSec: 0.27 });
if (!result.allowed) {
  console.log(`aguardar ${result.retryInMs}ms`);
  return;
}
// envia mensagem

Throttle dinâmico baseado em erro

Token bucket fixo é bom, mas pode estar errado. Imagine: você configurou 1k msgs/hora, mas o WhatsApp está nervoso hoje e devolvendo 30% de erro. Continuar enviando piora a situação. Reduza a vazão quando erro sobe:

// dynamic-rate.ts
const ERROR_WINDOW_MS = 60_000;
const errors: Map = new Map();

function recordError(instanceId: string) {
  const arr = errors.get(instanceId) ?? [];
  arr.push(Date.now());
  errors.set(instanceId, arr);
}

function recentErrorRate(instanceId: string): number {
  const arr = errors.get(instanceId) ?? [];
  const now = Date.now();
  const recent = arr.filter(t => now - t < ERROR_WINDOW_MS);
  errors.set(instanceId, recent);
  // Assume 1 mensagem/seg de baseline; erros recentes / janela
  return recent.length / (ERROR_WINDOW_MS / 1000);
}

function adjustedRate(baseRate: number, errorRate: number): number {
  if (errorRate > 0.10) return baseRate * 0.3;   // 30% original
  if (errorRate > 0.05) return baseRate * 0.6;
  return baseRate;
}

Sliding window vs token bucket vs leaky bucket

Comparação rápida:

  • Token bucket: permite burst até a capacity, refill constante. Bom para "1.000 msgs/hora mas posso enviar 100 de uma vez". Recomendado para WhatsApp.
  • Leaky bucket: taxa de saída fixa, sem burst. Bom para "1 msg a cada 800ms, sem exceção". Mais conservador.
  • Sliding window: conta últimos N requests em janela rolante. Mais preciso mas custoso (precisa armazenar timestamps).
  • Fixed window: simples, mas vulnerável a "quebra na borda" — 1k mensagens nas últimas 5s da janela + 1k nos primeiros 5s da próxima = 2k/10s.

Recomendação: token bucket para envio (permite ráfagas controladas), sliding window para análise de violações.

Warmup de número novo

Receita testada para subir um número de 0 a 5k msgs/dia em 30 dias sem ban:

const warmupSchedule = [
  { day: 1,  maxPerHour: 5,   total: 30 },
  { day: 2,  maxPerHour: 10,  total: 60 },
  { day: 3,  maxPerHour: 15,  total: 90 },
  { day: 7,  maxPerHour: 50,  total: 300 },
  { day: 14, maxPerHour: 150, total: 800 },
  { day: 21, maxPerHour: 400, total: 2000 },
  { day: 30, maxPerHour: 800, total: 5000 },
];

function getCurrentLimit(numberCreatedAt: Date): { perHour: number; perDay: number } {
  const days = Math.floor((Date.now() - numberCreatedAt.getTime()) / (24 * 60 * 60 * 1000));
  const slot = warmupSchedule.findLast(s => s.day <= days) ?? warmupSchedule[0];
  return { perHour: slot.maxPerHour, perDay: slot.total };
}

Acima disso, deixe o número crescer organicamente. Aumentos abruptos (50 para 5000 num dia) acendem alerta de spam.

Casos práticos

Caso 1: SaaS de cobrança que perdia números

Antes de implementar token bucket, perdia 1-2 números/mês para banimento. Pico era no dia 1 (cobrança em massa). Após implementar throttle dinâmico (1k/hora baseline com redução para 300/hora se erro >5%), zero banimentos em 8 meses.

Caso 2: Loja virtual com 4 números operacionais

Distribui carga entre 4 números via round-robin com peso. Número mais antigo (2 anos) recebe 50% do volume, dois aquecidos (6+ meses) recebem 20% cada, número novo está em warmup recebendo 10%. Aumentou capacidade total sem queimar nenhum.

Caso 3: Bot de atendimento 24/7

Throttle por usuário também — limita 5 mensagens do bot para o mesmo cliente em 60 segundos. Evita loops onde bot responde a si mesmo (cenário comum quando integra com IA generativa). Implementou em sliding window per-user, custo Redis irrisório.

FAQ

Qual algoritmo usar?

Token bucket por instância (controla volume) + sliding window por destino (evita spam para o mesmo número) + warmup escalado (números novos). Os 3 juntos protegem 95% dos cenários.

Como sincronizo o bucket entre múltiplos workers?

Redis com Redlock (mostrado acima). Cada worker faz takeToken via lock distribuído — mesmo com 10 workers paralelos, o estado fica consistente.

O que faço quando recebo 429?

Leia o header Retry-After e respeite. Coloque a mensagem de volta na fila com delay. Não retry imediato — vai estourar de novo.

Como observo o rate limit em produção?

Exporte métricas Prometheus: rate_limit_tokens{instance="..."}, rate_limit_throttled_total, rate_limit_429_total. Crie alerta: tokens=0 por >5min indica que o limite está apertado para o volume — aumente capacity ou refill.

Número novo, qual o ideal nos primeiros 7 dias?

5-30 mensagens/dia, distribuídas (não 30 num minuto). Idealmente, mensagens reais para contatos reais que respondem — interação cria sinal positivo com o WhatsApp. Disparo em massa em número novo é receita de banimento garantido.

Próximo passo

Implemente os 3 layers (token bucket + dynamic + warmup) em uma tarde. Criar conta grátis e ative o monitoramento de rate limit no painel desde o dia 1.

Experimente a ZAP API gratuitamente

7 dias de trial sem precisar de cartão. A partir de R$29/mês*.

Criar instância grátis
EE
Equipe Editorial ZAP APIRevisão técnica

Desenvolvedores e especialistas em integrações WhatsApp. Todo conteúdo passa por revisão técnica para garantir precisão e aplicabilidade.

Ver perfil completoDocumentaçãoTrial grátis

Leia também

Arquitetura · 15 de mai. de 2026 · 13 min

Circuit breaker em WhatsApp API: proteja sua instância de sobrecarga

Implemente circuit breaker para sua integração WhatsApp: evite cascata de falhas, proteja sua instância de rate limiting e garanta degradação graciosa.

Arquitetura · 30 de mai. de 2026 · 13 min

Mensagem idempotente no WhatsApp: nunca envie a mesma mensagem duas vezes

Como implementar idempotência em disparos WhatsApp para evitar mensagens duplicadas em retries, falhas de rede e race conditions em sistemas distribuídos.

Arquitetura · 26 de mai. de 2026 · 14 min

Multi-instância WhatsApp: arquitetura para escalar sem banimento

Como distribuir envios entre múltiplas instâncias WhatsApp para escalar volume, isolar clientes e proteger números críticos de banimento por sobrecarga.

Arquitetura · 10 de mai. de 2026 · 13 min

Cobrança PIX via WhatsApp: integração completa com QR Code

Como integrar cobrança PIX ao WhatsApp: gerar QR Code, enviar pelo chat, receber confirmação de pagamento via webhook e atualizar o status automaticamente.

Tópicos:Chatbots com IAE-commerceAPI WhatsApp

Explore também

Casos de usoWhatsApp API por segmentoComparativoZAP API vs alternativasPreçosPlanos e o que está inclusoGlossárioTermos técnicos de WhatsApp API
ZAP-API

API REST para WhatsApp com webhooks assinados, Meta Pixel/CAPI e compliance LGPD. Sem aprovação da Meta.

Status operacional🇧🇷 Feito no Brasil

Produto

  • Preços
  • Casos de uso
  • Comparativo
  • Trial grátis
  • Dashboard

Recursos

  • Documentação
  • Blog
  • Glossário
  • RSS Feed

Empresa

  • Sobre
  • Imprensa
  • Termos de uso
  • Privacidade
  • Criar conta
  • Login

Contato

  • [email protected]
  • [email protected]
  • Resposta em até 24h úteis
© 2026 ZAP-API — Todos os direitos reservados·CNPJ 42.130.949/0001-56·Termos·Privacidade

Desenvolvido por PreviusIA