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:
| Constante | Nombre en Meta |
|---|---|
CONFIRMATION_DELIVERY_TODAY | confirmacion_entrega_hoy |
REMITTANCE_NOTIFICATION_V2 | envio_remito_notificacion_v2 |
REMITTANCE_NOTIFICATION_TEXT | envio_remito_notification_text |
FAILED_DELIVERY | envio_fallido |
START_DELIVERY | envio_comienzo |
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— nuestroEntityStatusinterno.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
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.