Ir al contenido

Envío masivo seguro

WhatsApp no publica sus umbrales de detección de spam. Esta capa aplica heurísticas para que el tráfico de la API se parezca al de una persona usando WhatsApp, no al de un servidor. Ninguna de estas medidas garantiza evitar un baneo — ver limitaciones.

SendQueueService mantiene una cola serial por sesión: nunca dos mensajes de la misma sesión salen en simultáneo. Entre mensaje y mensaje espera un delay aleatorio (WA_SEND_MIN_DELAY_MS–WA_SEND_MAX_DELAY_MS, default 8–25s) — un delay fijo sería tan detectable como no tener delay. Cada WA_LONG_PAUSE_EVERY mensajes (default 25) hace además una pausa larga (WA_LONG_PAUSE_MS, default 3 min), simulando que la persona dejó el teléfono.

Cada sesión tiene una SessionThrottlePolicy (se crea con los defaults vigentes la primera vez que se necesita, y queda fija para esa sesión desde entonces) con límites por hora y por día — por defecto WA_SEND_MAX_PER_HOUR=60 y WA_SEND_MAX_PER_DAY=300.

Warmup y quiet hours vienen desactivados por defecto. Son las dos protecciones más agresivas — pueden retrasar un envío horas — y no toda cuenta las necesita. Si los activás (WA_WARMUP_ENABLED=true), una cuenta nueva no arranca con el límite completo: hay una rampa progresiva desde warmupStartedAt:

Día Máx./día Máx./hora
1–2 20 5
3–5 50 12
6–10 100 25
11–20 200 40
21+ WA_SEND_MAX_PER_DAY WA_SEND_MAX_PER_HOUR

Quiet hours (WA_QUIET_HOURS_START/WA_QUIET_HOURS_END), si se configuran con un rango real (por ejemplo 22–08), bloquean envíos en esa franja horaria de la sesión. Un schedule que cae en cuota agotada o en quiet hours no falla — se reprograma automáticamente para cuando vuelva a ser posible.

Antes de cada envío (si WA_VALIDATE_NUMBER_EXISTS=true, default):

  1. Se valida que el número exista en WhatsApp (onWhatsApp()). Mandarle a números inexistentes es una señal fuerte de lista comprada/scrapeada — si no existe, el schedule se marca failed sin consumir cuota. El resultado se cachea 7 días por número para no repreguntar todo el tiempo (eso también es un patrón detectable).
  2. Se simula tipeo (si WA_SIMULATE_TYPING=true, default): composing → pausa proporcional al largo del mensaje (~70ms/carácter, tope 8s) → paused → recién ahí se envía. Un mensaje largo que aparece con 0ms de tipeo es imposible para un humano.

Enviar el mismo texto literal a muchos destinatarios es trivialmente detectable. Las plantillas soportan spintax — {Hola|Buenas|Qué tal} — que resuelve una opción al azar en cada render. Ver Plantillas.

La sesión escucha señales directas de WhatsApp y se pausa sola cuando corresponde:

  • reachoutTimeLock — WhatsApp restringe temporalmente el contacto a números nuevos. La sesión se pausa hasta que WhatsApp indica que se levantó.
  • Desconexiones no recuperables (forbidden, badSession, connectionReplaced, multideviceMismatch) — la sesión no reintenta en loop; queda en error con una pausa larga y requiere re-vinculación manual.
  • 3 fallos de envío consecutivos — pausa de 30 minutos por precaución, incluso si la sesión sigue “conectada”.

Podés consultar el estado de todo esto con GET /sessions/:id/health, que devuelve si está pausada, por qué, y las cuotas consumidas.

Variables de entorno (todas con default conservador; una política por sesión en base de datos las puede sobrescribir):

WA_SEND_MIN_DELAY_MS=8000
WA_SEND_MAX_DELAY_MS=25000
WA_SEND_MAX_PER_HOUR=60
WA_SEND_MAX_PER_DAY=300
WA_WARMUP_ENABLED=false
WA_QUIET_HOURS_START=0
WA_QUIET_HOURS_END=0
WA_VALIDATE_NUMBER_EXISTS=true
WA_SIMULATE_TYPING=true
WA_LONG_PAUSE_EVERY=25
WA_LONG_PAUSE_MS=180000

WA_QUIET_HOURS_START igual a WA_QUIET_HOURS_END (default 0/0) desactiva la ventana — no hay ninguna hora bloqueada.

Baileys es un cliente no oficial; usar WhatsApp Web de forma automatizada viola sus Términos de Servicio, y estas heurísticas reducen el riesgo pero no lo eliminan. Para envío masivo con garantías contractuales, la vía oficial es la WhatsApp Business Platform (Cloud API).