Skip to main content

WhatsApp (Meta)

Avisa al paciente del envío de su remito, del comienzo de la entrega, de un envío fallido y de la confirmación de entrega del día; y recibe sus respuestas.

Cómo se habla: Meta Cloud API, con plantillas aprobadas — fuera de la ventana de 24 h no se puede mandar texto libre. Entrada por webhook, salida por cola RabbitMQ.

Estructura del módulo

src/modules/whatsapp/
├── providers/IWhatsAppProvider.ts # la interfaz: sendMessage + uploadMedia
├── providers/MetaWhatsAppProvider.ts # la implementación
├── factory/WhatsappProviderFactory.ts # elige por env WHATSAPP_PROVIDER (default "meta")
├── WhatsAppTemplateManager.ts # armado de plantillas y parámetros
├── WhatsAppWorker.ts # los dos consumidores de cola
├── services/WhatsAppService.ts # envío
├── services/WhatsAppWebhookService.ts # procesamiento de eventos entrantes
├── controllers/ # API + webhook
├── utils/WhatsAppSignatureValidator.ts
└── enums/ # plantillas y estados

Flujo

El worker corre con EXECUTION_MODE=whatsapp.

Plantillas registradas

El valor del enum es el nombre exacto aprobado en Meta, no un alias interno:

ConstanteNombre en Meta
CONFIRMATION_DELIVERY_TODAYconfirmacion_entrega_hoy
REMITTANCE_NOTIFICATION_V2envio_remito_notificacion_v2
REMITTANCE_NOTIFICATION_TEXTenvio_remito_notification_text
FAILED_DELIVERYenvio_fallido
START_DELIVERYenvio_comienzo
Una plantilla nueva se da de alta en Meta primero

Agregar la constante al enum no alcanza: Meta tiene que tenerla aprobada, con la misma cantidad y orden de parámetros. Si no, el envío falla en runtime.

Persistencia

logs.WHATSAPPMESSAGES, con doble tracking:

  • state — nuestro EntityStatus interno.
  • status — el estado en Meta: sent / delivered / read / replied / failed.

Más lastResponse (la respuesta del paciente, por ejemplo el click de un botón), templateName y metadata.

En la consola web esto se ve en la pantalla Mensajes.

Gotchas

La ruta del webhook es pública a la fuerza

isPublicRoute() devuelve true para /v1/whatsapp/webhook hardcodeado, sin importar PUBLIC_ROUTES. La autenticidad la valida WhatsAppSignatureValidator, no el middleware de auth. Si tocás esa ruta, no rompas la validación de firma.

El factory tira si WHATSAPP_PROVIDER no es "meta". No hay otro provider implementado; la interfaz existe para poder cambiarlo sin tocar los servicios.

Variables de entorno

Solo nombres: WHATSAPP_PROVIDER, WHATSAPP_TOKEN, WHATSAPP_APP_SECRET, WHATSAPP_PHONE_NUMBER_ID, WHATSAPP_WEBHOOK_VERIFY_TOKEN, WHATSAPP_TEMPLATE_NAME, WHATSAPP_TEMPLATE_LANG, WHATSAPP_TEST_PHONE.