---
title: "Lista de contactos para WhatsApp: opt-in, limpieza y opt-out automático"
description: "La lista decide el resultado del envío antes de que salga el primer mensaje. Cómo registrar un opt-in que sirva de prueba, limpiar números inválidos antes de enviar, procesar el opt-out automáticamente y medir la salud de la base."
url: "https://wame.api.br/blog/lista-contactos-optin-optout-whatsapp"
language: "pt-BR"
og:type: "article"
published_time: "2026-09-10"
modified_time: "2026-09-10"
author: "Raphael Serafim"
keywords: "opt-in whatsapp, opt-out whatsapp, lista de contactos whatsapp, baja whatsapp automática, limpiar lista whatsapp, validar número whatsapp, envío masivo whatsapp lista"
reading_time: "9 min de lectura"
---

# Lista de contactos para WhatsApp: opt-in, limpieza y opt-out automático

> La lista decide el resultado del envío antes de que salga el primer mensaje. Cómo registrar un opt-in que sirva de prueba, limpiar números inválidos antes de enviar, procesar el opt-out automáticamente y medir la salud de la base.

**La lista decide el resultado del envío antes de que salga el primer mensaje.** Puedes acertar la plantilla, el ritmo y el horario, y aun así quemar el número — si la lista está mal.

Este artículo trata de la lista. Sobre la mecánica del volumen, está [cola, rate limit y reintentos](/blog/cola-rate-limit-reintentos-envio-masivo-whatsapp).

## Un opt-in que sirva de prueba

Casi todo sistema guarda el consentimiento así:

```sql
acepta_whatsapp BOOLEAN DEFAULT FALSE
```

Eso no es un registro de consentimiento. Es una afirmación sin prueba — y el día que alguien lo cuestione, no tienes qué mostrar.

El registro útil guarda **circunstancia**:

```sql
CREATE TABLE optin_whatsapp (
  id            BIGSERIAL PRIMARY KEY,
  contacto_id   BIGINT NOT NULL,
  numero        VARCHAR(20) NOT NULL,
  aceptado_en   TIMESTAMPTZ NOT NULL,
  origen        VARCHAR(50) NOT NULL,   -- checkout | formulario | atencion
  texto_mostrado TEXT NOT NULL,         -- lo que la persona leyó al aceptar
  ip            INET,
  user_agent    TEXT,
  revocado_en   TIMESTAMPTZ             -- NULL = activo
);
```

El campo que más falta en los sistemas es `texto_mostrado`. El consentimiento es para una finalidad: quien aceptó "recibir novedades de mi pedido" no aceptó una promoción semanal. Guardar el texto es lo que te permite responder *para qué* dijo que sí.

`revocado_en` en lugar de `DELETE`: borrar el registro borra también la prueba de que hubo consentimiento antes. El historial es la defensa.

### Lo que no es opt-in

- Lista comprada.
- Números raspados de un sitio, un grupo o un marketplace.
- "El que no quiera que avise."
- Base de hace cinco años sin contacto desde entonces.
- Consentimiento para correo reutilizado para WhatsApp.

Todos funcionan un tiempo. Todos terminan igual: bloqueo, denuncia, calidad del número por el piso, plantilla pausada.

## Limpiar antes de enviar

Un número inválido no es solo desperdicio: en la API oficial, el intento de entrega fallido cuenta en contra de la reputación. Conviene filtrar antes.

**Normaliza primero.** Una base latinoamericana trae de todo: `(55) 5512-3456`, `+52 55 5512 3456`, `04455...`.

```js
function normalizar(bruto, paisPorDefecto = '52') {
  let n = String(bruto).replace(/\D/g, '');

  // Quita el cero o el prefijo de larga distancia inicial
  n = n.replace(/^0+/, '');

  // Sin código de país, asume el del país de la operación
  const codigos = ['52', '54', '56', '57'];   // MX, AR, CL, CO
  if (!codigos.some((c) => n.startsWith(c))) n = paisPorDefecto + n;

  if (n.length < 10 || n.length > 15) return null;
  return n;
}
```

**Después comprueba quién tiene WhatsApp de verdad:**

```js
async function limpiar(numeros) {
  const validos = [];
  for (const bruto of numeros) {
    const n = normalizar(bruto);
    if (!n) { await marcar(bruto, 'formato_invalido'); continue; }

    const existe = await wa.contact.checkNumber(n);
    if (!existe) { await marcar(n, 'sin_whatsapp'); continue; }

    validos.push(n);
    await esperar(200);   // la verificación también tiene límite
  }
  return validos;
}
```

Hazlo **antes** de la campaña, no durante. Y guarda el resultado: reverificar la base entera en cada envío es desperdicio.

## Opt-out automático

Ignorar un pedido de baja es el camino más rápido a la denuncia — y una denuncia pesa mucho más que un bloqueo.

```js
const BAJA = /^\s*(salir|parar|baja|cancelar|eliminar|stop|no)\s*!?\.?\s*$/i;

async function procesar(msg) {
  if (BAJA.test(msg.text.body)) {
    await registrarOptOut(msg.from);
    await enviar(msg.from, 'Listo, no volverás a recibir nuestros mensajes. ' +
                           'Si necesitas algo, escríbenos por acá.');
    return;   // no sigue a la atención normal
  }
  await atencionNormal(msg);
}
```

La expresión regular exige que sea el mensaje **completo**, a propósito. Buscar la palabra suelta marcaría como baja a quien escribió "quiero cancelar mi pedido", que es un cliente pidiendo atención, no una baja.

**El error que casi todos cometen:** revisar el opt-out solo al armar la campaña. Una campaña de 50 mil contactos tarda horas en drenar, y quien pide salir en el minuto 10 sigue recibiendo por horas. La comprobación tiene que estar **al momento de enviar cada mensaje**:

```js
// en el worker, justo antes del envío
if (await estaEnOptOut(job.data.to)) return;   // salió después de encolarse
```

Y deja la salida visible. Un "responde SALIR para no recibir más" al pie de la plantilla convierte denuncias en bajas — la diferencia entre perder un contacto y lastimar el número.

## Medir la salud de la base

Tres indicadores, por campaña:

| Indicador | Qué observar |
|---|---|
| **Tasa de entrega** | Por debajo del 95%, hay números muertos: toca limpiar |
| **Bloqueos** | Si suben, el contenido no corresponde a lo que se consintió |
| **Denuncias** | Cualquier aumento es grave; es lo que más tumba números |

Si los bloqueos y las denuncias suben, **enviar más empeora**. La respuesta es bajar la frecuencia, revisar el contenido y reconfirmar el opt-in de los contactos antiguos.

## Reconfirmar una base antigua

Una base parada más de un año es prácticamente una base nueva, y dispararle promociones es pedir denuncias. El camino seguro es un único mensaje de utilidad, con salida explícita:

> ¡Hola, Ana! Hace tiempo que no hablamos. ¿Quieres seguir recibiendo novedades de Tienda Ejemplo por acá? Responde **SÍ** para continuar o **SALIR** para no recibir más.

Quien no responde no es un "sí". Es silencio — y el silencio, en la duda, se trata como una baja.

## Conclusión

Una buena lista es una lista lo bastante chica como para que sepas de dónde salió cada contacto. La tentación de enviarle a todo el mundo es fuerte, y el costo aparece una campaña después.

Opt-in con prueba, limpieza antes del envío, opt-out comprobado al momento de enviar y tres indicadores vigilados. Ninguna de las cuatro cosas es difícil — todas son tediosas, y por eso casi nadie las hace.

## Perguntas frequentes

### ¿Qué es el opt-in en WhatsApp y cómo se registra?

Es el consentimiento de la persona para recibir tus mensajes en ese canal. Registrarlo significa guardar cuándo, dónde y cómo se dio: fecha y hora, origen (formulario, checkout, atención), el texto que se mostró en ese momento y el identificador de la sesión. Una columna booleana 'aceptó' no es un registro de consentimiento: es una afirmación sin prueba.

### ¿Cómo saber si un número tiene WhatsApp antes de enviar?

La API tiene verificación de número. Correr esa comprobación sobre la base antes del envío elimina los inválidos, y eso importa porque en la API oficial un intento de entrega fallido cuenta en contra de la reputación de tu número.

### ¿Cómo funciona el opt-out automático?

Detectas en el webhook las palabras de baja (salir, parar, baja, cancelar), marcas al contacto como opt-out antes de cualquier otro procesamiento y se lo confirmas. El punto crítico es que la comprobación de opt-out ocurra al momento de encolar cada envío, no solo al armar la campaña.

### ¿Necesito opt-in también en la API no oficial?

Legalmente sí: las leyes de protección de datos de la región regulan el tratamiento de datos personales, no la tecnología que uses para enviar. En la práctica también, porque los bloqueos y las denuncias de usuarios tumban cualquier número. La API no oficial no fiscaliza el opt-in, lo que aumenta tu responsabilidad en lugar de reducirla.

### ¿Cuántos mensajes aguanta mi base antes de quemarse?

No es el volumen lo que quema, es la tasa de rechazo. Una base de 50 mil contactos con opt-in reciente y contenido esperado tiene menos problemas que una de 500 comprada. Sigue los bloqueos y denuncias por campaña: cuando ese número sube, el problema es la lista o el contenido, y enviar más solo acelera el daño.
