Rate Limits de Mensageria — Wasender API
Constante centralizada:
supabase/functions/_shared/messaging-rate-limits.ts(backend) esrc/lib/messaging-rate-limits.ts(frontend).
Plano Atual: Basic ($6/mês)
| Recurso | Limite |
|---|---|
| Send Message | 256 requests/minuto por sessão |
| Sessões WhatsApp | 1 |
| Mensagens/mês | Ilimitadas (sem custo por mensagem) |
| Cap diário | Sem limite (apenas Trial tem 50/dia) |
| Account Protection Mode | Se ativado: 1 req/5s (12/min) — sobrescreve limite do plano |
Tabela Comparativa de Planos
| Plano | Preço/mês | Send Message/min | Sessões | Cap diário |
|---|---|---|---|---|
| Trial | Grátis | 256 | 1 | 50 msgs |
| Basic | $6 | 256 | 1 | Ilimitado |
| Pro | $12 | 256 | 3 | Ilimitado |
| Plus | $18 | 256 | 5 | Ilimitado |
| Business | $30 | 256 | 10 | Ilimitado |
Nota: O rate limit de 256/min é por sessão e aplica-se a todos os planos pagos. A diferença entre planos é o número de sessões simultâneas.
Proteções Implementadas
1. Cooldown no Frontend (Reenviar OTP)
- Valor: 60 segundos entre reenvios
- Onde:
src/components/login-unified.tsx— botão "Reenviar código" - Constante:
MESSAGING_RATE_LIMITS.cooldownReenvioOtpSegundos - Comportamento: Após envio de OTP, botão mostra countdown "Reenviar em Xs" e fica desabilitado
- Natureza: Apenas UX — a proteção real é no backend
2. Rate Limit no Backend (OTP) — PROTEÇÃO REAL
- Por usuário: Máximo 3 OTPs em 15 minutos (query em
login_otpsporusuario_id) - Por IP: Máximo 10 OTPs em 1 hora (query em
login_otpsporip_origem) - Onde: Edge Function
send-otp - Resposta: HTTP 429 quando excedido
- Proteção contra: CURL, bots, requisições em massa — qualquer client
3. Adapter Centralizado
- Todo envio passa por
enviarMensagemComLog()em_shared/wasender-whatsapp.ts - Ponto único de envio via WhatsApp (Wasender)
- Ponto único para aplicar throttle futuro
Guia para Envio em Massa (Futuro)
Conta correta
text
Limite do plano: 256 requests/minuto por sessão
Plano Basic: 1 sessão
Configuração segura:
1 worker sequencial × delay de 275ms ≈ 3.6 msgs/segundo ≈ 218 msgs/minuto
218/256 = 85% do limite → margem de 15%
Nota: O erro anterior era usar MÚLTIPLOS workers (3×250ms = 720/min = BAN).
Com 1 worker, o delay de 275ms é seguro.Implementação
typescript
import { MESSAGING_RATE_LIMITS } from "../_shared/messaging-rate-limits.ts";
// Fila sequencial — NUNCA paralela
for (const destinatario of lista) {
await enviarMensagemComLog(destinatario, mensagem);
await delay(MESSAGING_RATE_LIMITS.delayEntreEnviosMs); // 275ms
}Por que NÃO usar concorrência
A documentação do Wasender afirma que alta concorrência é a causa #1 de ban do WhatsApp.
Com 1 sessão (plano Basic), múltiplos workers disparam requests simultâneos contra o mesmo limite:
text
❌ 3 workers × 250ms delay = 12 msgs/s = 720 msgs/min (BAN CERTO)
❌ Promise.all sem controle = rajada instantânea (BAN CERTO)
✅ 1 worker × 275ms delay = 3.6 msgs/s ≈ 218 msgs/min (seguro, margem 15%)Concorrência só faria sentido com múltiplas sessões (planos Pro+), e mesmo assim, 1 worker por sessão.
Recomendações
- Fila sequencial — 1 worker,
await delay(275)entre cada mensagem - Checar sessão — Validar status via
check_whatsapp_sessionantes de iniciar bulk - Circuit breaker — Se 3 falhas consecutivas, pausar fila por 30s e alertar via ntfy
- Monitorar — Logar cada envio, acompanhar taxa de sucesso
Anti-padrões
| ❌ Errado | ✅ Correto |
|---|---|
Promise.all(msgs.map(enviar)) — rajada sem controle | Fila sequencial com await delay(275) |
| Múltiplos workers na mesma sessão | 1 worker sequencial por sessão |
| Enviar 1000 msgs sem checar sessão | Validar sessão antes, pausar se desconectada |
| Ignorar erros e continuar enviando | Circuit breaker após 3 falhas consecutivas |
Glossário
| Termo | Significado |
|---|---|
| Throttle | Limitar a velocidade de envio (delay fixo entre mensagens). Correto e necessário. |
| Concorrência | Múltiplos workers enviando em paralelo. Anti-padrão para 1 sessão — multiplica requests contra o mesmo limite. |
| Circuit breaker | Padrão que pausa envios após N falhas consecutivas para evitar cascata de erros. |
Checklist: Mudança de Plano
markdown
□ Atualizar `MESSAGING_RATE_LIMITS.plano` e `custoMensal`
□ Atualizar `sessoesDisponiveis` se mudou
□ NÃO aumentar `maxConcorrencia` além de 1 por sessão
□ Verificar se `accountProtectionMode` está habilitado no dashboard Wasender
□ Atualizar tabela comparativa neste documento
□ Testar bulk sending com novos valoresHistórico
| Data | Mudança |
|---|---|
| 2026-03-30 | Documento criado. Constante centralizada + cooldown 60s no reenviar OTP. |
| 2026-03-30 | Correção: concorrência 3→1, delay 250ms→1000ms. Conta anterior estava errada (720/min vs 256 limite). |