4dim / Notas
Tres canales de Meta, dos formatos de webhook
WhatsApp llega en entry[].changes[]; Messenger e Instagram, en entry[].messaging[]. El eco que abre una ventana falsa, los acuses que se aplican por id y nunca por hora, y los avisos que llegan desordenados. Lo que hay que saber antes de decir que el webhook «funciona».
Un webhook, tres canales
Si vas a juntar WhatsApp, Messenger e Instagram en un mismo sistema, esta nota te dice en qué se diferencian por dentro y dónde se rompe la cosa. Son de la misma empresa y se configuran en el mismo panel, así que uno espera que hablen igual. No hablan igual.
Un solo webhook recibe los tres. El webhook es la dirección a la que Meta le entrega al negocio cada mensaje que llega. Lo primero que tiene que hacer es mirar el campo object del sobre para saber quién le escribe: whatsapp_business_account, page o instagram. A partir de ahí, dos formatos distintos.
La forma del sobre
| Messenger e Instagram | ||
|---|---|---|
object | whatsapp_business_account | page / instagram |
| Dónde vienen los mensajes | entry[].changes[], con field: "messages" y los mensajes dentro de value.messages | entry[].messaging[], un evento por mensaje, sin nivel changes |
| Quién recibió | phone_number_id | El id de la página o de la cuenta de Instagram |
| Del remitente | wa_id, nombre del perfil | Id con ámbito de aplicación |
| Adjuntos | Un media_id que hay que canjear | Una URL ya resuelta |
| Acuses de entrega | Estados por id de mensaje | Eventos delivery y read con listas de ids |
Durante un tiempo nuestro webhook solo entendía el primer formato. Los mensajes de Messenger e Instagram llegaban, respondíamos 200, el código que le dice a Meta que llegó, y no pasaba nada más. El programa buscaba changes donde había messaging.
La ventana de 24 horas de esos canales nunca se abría, porque nunca se registraba el mensaje que la abre. Esa ventana es el plazo para contestarle con texto libre a quien te escribió.
El eco que abre una ventana falsa
Messenger e Instagram te devuelven por el webhook tus propios mensajes. Cada respuesta que manda el negocio vuelve como un evento marcado con is_echo: true. Eso es un eco.
Si el eco se procesa como si fuera entrante, cada respuesta del negocio aparece en la bandeja como si la hubiera escrito el cliente. Y peor: abre una ventana de 24 horas que en realidad no está abierta, porque la ventana la abre el cliente, no el negocio.
El sistema cree que puede escribir libre, Meta lo rechaza, y el mensaje no sale. Los ecos se descartan en la primera línea del tratamiento. WhatsApp no los manda, así que quien viene de WhatsApp no espera encontrarlos.
Acuses por id, nunca por marca de tiempo
Los eventos de entrega y lectura de Messenger traen a veces una lista de identificadores de mensaje. Otras veces traen solo una marca de tiempo: «todo lo anterior a esta hora está leído». La segunda forma es tentadora porque es más fácil.
Nosotros usamos solo la lista de ids y descartamos la marca de tiempo. Subir la conversación entera a «leído» por una hora pintaría como leídos mensajes que Meta no dijo que lo estuvieran. Y un «leído» que no es cierto es la mentira que se paga con una venta.
Los avisos llegan desordenados
En los tres canales, los estados de un mensaje que sale suben por una escalera: encolado, enviado, recibido, leído. Los avisos de Meta no llegan en ese orden. Es normal recibir «recibido» después de «leído». Si cada aviso escribe su estado tal cual, el mensaje retrocede en pantalla.
Por eso la actualización compara el peldaño dentro de la propia sentencia SQL, la orden con la que se escribe en la base de datos, y solo deja avanzar. Dos avisos que llegan a la vez no pueden pisarse, porque comparar y escribir son un solo paso.
La única excepción es «fallido», que puede sobrescribir cualquier estado en cualquier dirección. Si Meta dice que falló, falló. Y un mensaje fallido no vuelve a subir.
De Meta no se asume ni el orden ni la forma. Se lee lo que viene, se mira de qué canal es, y se compara antes de escribir.
Qué hacer entonces
- Reparte por
objectantes de tocar nada. - Usa dos analizadores, uno por formato. No intentes una tabla común con excepciones: la excepción de una tabla es por donde se cuela el que no era.
- Descarta
is_echolo primero. - Toma los acuses por id de mensaje. La marca de tiempo se ignora.
- Escribe los estados comparando el peldaño en la misma orden, con «fallido» como única excepción.
- Prueba el webhook con los tres canales reales, no solo con WhatsApp. Lo que no se prueba responde 200 y no hace nada.
Esta nota sale de nuestro trabajo en AI-CRM Connection.