Changelog

Qué cambia en la API

Cambios de endpoint, de envelope de webhook y de comportamiento, en orden cronológico. Los campos nuevos son aditivos: nada de lo que ya recibes deja de llegar sin avisarse aquí.

Adición es compatible con lo que ya haces. Corrección cambia lo que recibes, hacia lo que ya estaba documentado. Requiere atención cambia el comportamiento de quien no haga nada.

  1. Requiere atenciónChatwootWhatsApp Oficial

    Ventana de 24h: el mensaje libre fuera de ella ya no se envía

    En la cuenta oficial, pasadas 24h del último mensaje del cliente, el texto libre ya no se intenta: o sale como plantilla aprobada, o se convierte en un aviso en la conversación.

    Meta rechaza cualquier mensaje libre fuera de la ventana de 24 horas. Hasta ahora el intento salía de aquí, era rechazado allá y el error quedaba solo en el log: el agente veía el mensaje como enviado.

    Qué cambia:

    • Si el texto que escribió el agente corresponde a una plantilla aprobada, el envío sale como plantilla y la conversación se reabre. Las variables se extraen del propio texto, así que puede editar la plantilla antes de enviar.
    • Si no corresponde, no se envía nada: una nota privada explica el motivo y el mensaje queda marcado como fallido.
    • POST /chatwoot/templates/sync publica las plantillas aprobadas como respuestas rápidas (atajo tpl_<nombre>), que es como el agente dispara una sin salir del panel.

    Cuando no sabemos cuándo habló el cliente por última vez, el envío sigue normal — Meta sigue siendo quien decide.

  2. CorrecciónChatwoot

    Chatwoot: la cuenta se descubre por la bandeja de entrada

    Quien usa un único Token de Acceso para varias cuentas de Chatwoot tenía los mensajes enviados desde el celular escritos en la cuenta equivocada — o rechazados con 404.

    El account_id se descubría por el perfil del Token de Acceso, que devuelve la cuenta activa del usuario — sin relación con la cuenta dueña de la bandeja configurada. En un bot de automatización que atiende decenas de cuentas con un solo token, eso apuntaba a la cuenta equivocada.

    Ahora la cuenta se descubre buscando el inbox_identifier configurado entre las bandejas de cada cuenta que el token alcanza. Cuando el barrido no la encuentra en ninguna, no se escribe nada: el log explica el motivo, en vez de que el mensaje acabe en la conversación de otro cliente.

    No necesitas hacer nada. Si tu integración funcionaba, sigue igual.

  3. CorrecciónChatwootWhatsAppWhatsApp Oficial

    Chatwoot: cinco fallas en el espejo de las conversaciones

    El mensaje cuyo archivo no se podía descargar desaparecía del panel; las marcas de entregado/leído nunca funcionaron en WhatsApp no oficial; los adjuntos más allá del primero se descartaban.

    Una auditoría de la integración encontró cinco problemas, todos corregidos:

    • El mensaje del cliente desaparecía cuando el archivo no podía descargarse (más de 40 MB, descarga rechazada). Chatwoot rechaza un mensaje sin contenido y sin adjunto, y la conversación quedaba sin rastro. Ahora llega un aviso en lugar del silencio.
    • Las marcas de entregado y leído nunca funcionaron en WhatsApp no oficial: dependían de una configuración de tu webhook que nace apagada. El acuse ahora va directo a Chatwoot.
    • Un contacto identificado solo por LID se convertía en un teléfono inventado, y la respuesta del agente no llegaba a nadie.
    • Del segundo adjunto en adelante, no se enviaba nada cuando el agente adjuntaba varios archivos. Y todo documento llegaba como file.pdf en vez de su nombre real.
    • Un envío rechazado por el proveedor parecía entregado en el panel; ahora aparece como fallido.
  4. CorrecciónAPIWhatsApp Oficial

    Diagnóstico de webhook: la ruta de estadísticas pasa a hablar de tu instancia

    GET /instance/webhook/statistics respondía 500 en cuenta oficial y, cuando respondía, devolvía los contadores de la cola del servidor — iguales para todas las instancias. Ahora devuelve el resultado real de cada POST de tu instancia.

    La ruta tenía dos defectos que se sumaban.

    En cuenta oficial (Cloud API) respondía 500: por dentro pasaba por la sesión del código QR, que la cuenta oficial no tiene. Era justamente la instancia cuyo webhook da más trabajo la que no se podía diagnosticar. En una instancia de código QR aún no cargada en el servidor, el "no encontrada" también salía como 500.

    Y cuando respondía, los números eran los contadores de la cola del proceso — globales, compartidos por todas las instancias de ese servidor. Respondían "¿la cola está atascada?", nunca "¿el webhook de mi instancia salió, y qué respondió mi servidor?". La única respuesta a eso vivía en el log del servidor, fuera de tu alcance.

    Ahora la respuesta es sobre tu instancia:

    json
    {
      "status": 200,
      "data": {
        "official": true,
        "webhook": {
          "allowNumber": "all",
          "webhookFormat": "meta",
          "configured": ["webhookMessage", "webhookMessageFromMe"],
          "anyUrl": true
        },
        "delivery": {
          "queued": 118,
          "attempts": 118,
          "ok": 117,
          "clientError": 0,
          "failed": 1,
          "avgMs": 143,
          "last": { "ts": "2026-10-14T22:34:01.020Z", "status": 200, "ms": 131, "outcome": "ok" },
          "recent": []
        },
        "queue": { "waiting": 0, "active": 0, "failed": 0, "scope": "worker-global" }
      }
    }

    Cómo leerlo:

    • anyUrl: false — ningún canal tiene URL. Sin URL no hay nada que entregar: el evento sale solo por el socket. Es la causa número uno de "no recibo nada", y era lo que obligaba a abrir el log para descubrir lo obvio. configured dice qué canales tienen URL de hecho.
    • ok alto y aun así "no llega nada" — el POST salió y tu servidor respondió 2xx. El evento se perdió en tu procesamiento, no en el transporte. Ese era el caso que no dejaba ningún rastro.
    • clientError — tu servidor rechazó con 4xx. No reintentamos 4xx por diseño: un 404 o un 422 no mejora repitiendo.
    • failed — timeout, 5xx o 429. Esos sí los reintentamos: 5 intentos con retroceso exponencial. Nuestro tiempo límite de entrega es de 8 segundos.
    • queued muy por encima de attempts — la cola se trabó de nuestro lado. El problema no es tu servidor.
    • queue sigue en la respuesta, ahora marcada scope: "worker-global": son números del proceso, compartidos con otras instancias. Para juzgar la tuya, usa delivery.

    Letra pequeña: los contadores valen a partir de esta versión, no hay historial retroactivo. Se guardan 7 días, y recent trae las últimas 20 entregas con estado, duración y error. Vale para cuenta oficial (Cloud API) y código QR.

    En el mismo lote, /instance/webhook/error salió de la documentación — aparecía allí y nunca existió en la API.

  5. CorrecciónMessenger

    Messenger: las reacciones funcionan, y el sticker deja de llegar como imagen

    El endpoint de reacción enviaba un valor fijo en vez del emoji elegido, y Meta rechazaba todos los intentos. La reacción recibida y el sticker tampoco llegaban identificados.

    • Enviar reacción (/message/reaction con provider: messenger) descartaba el emoji y mandaba un valor fijo: Meta respondía 100/2018468 en todos los intentos. Ahora va el emoji que envíes. El formato aceptado es el emoji en UTF-8 (👍, ❤️); los nombres en texto (like) se rechazan de inmediato, con explicación. Quitar sigue siendo text: "".
    • Recibir reacción no se entregaba: el evento se descartaba antes de llegar a tu webhook. Ahora llega como mensaje type: "reaction", con reaction.message_id, reaction.emoji y reaction.action (react o unreact; al quitar, el emoji viene vacío).
    • Sticker llegaba como imagen común. Messenger lo entrega como adjunto que se declara image con sticker_id en el payload; ahora llega como type: "sticker" con ese id. Meta no expone el archivo animado en el webhook — la URL servida es la versión estática.
    • Foto del contacto: cuando la Graph rechaza el perfil, el motivo queda registrado en el log, en vez de que el contacto quede sin avatar sin explicación.
  6. AdiciónChatwoot

    Chatwoot: cita nativa, nota de voz y hora real

    Con el Token de Acceso configurado, la conversación en el panel gana burbuja de respuesta real, reproductor de voz y la hora en que el mensaje existió en el canal.

    La API pública de la bandeja acepta solo texto y adjunto. Con Token de Acceso, el mensaje del cliente pasa a crearse por la Application API, lo que habilita tres cosas:

    • Cita nativa: la respuesta aparece en la burbuja de Chatwoot, ya no como un fragmento citado dentro del texto.
    • Nota de voz con reproductor propio, en vez de un adjunto de audio cualquiera.
    • Hora real del mensaje: el backlog reentregado tras una caída de conexión ya no aparece amontonado en la hora de la entrega.

    Sin Token de Acceso nada cambia. Las citas a mensajes anteriores a esta versión aparecen sin burbuja, porque no tienen el identificador del canal guardado.

  7. AdiciónChatwootWhatsAppWhatsApp Oficial

    Chatwoot: “escribiendo…” en ambos sentidos y tilde azul al responder

    El cliente ve cuando el agente escribe, el agente ve cuando el cliente escribe, y responder desde el panel marca la conversación como leída en WhatsApp.

    Tres señales que existían en ambos extremos y nunca se encontraban:

    • Agente escribiendo → el cliente lo ve. En WhatsApp no oficial es presencia; en la cuenta oficial el indicador va junto al marcar-como-leído, como exige la Cloud API. "Dejó de escribir" no existe en la cuenta oficial: allí el indicador desaparece solo tras unos 25 segundos.
    • Cliente escribiendo → el agente lo ve en el panel. El indicador nunca abre una conversación nueva.
    • Responder desde el panel marca como leído en el canal, así el cliente deja de ver dos tildes grises mientras ya está siendo atendido.
  8. AdiciónMessengerAPI

    Webhook de Messenger: número de secuencia y marcas de tiempo

    Cada evento lleva ahora un bloque wame con un número de secuencia por conversación y tres horarios, para reconstruir el orden y medir dónde se fue el tiempo.

    La entrega de webhooks es paralela: el orden en que las solicitudes llegan a tu servidor es el orden en que cada una termina, no el orden en que entraron los eventos. Dos mensajes enviados en secuencia pueden llegar invertidos.

    En vez de serializar la entrega, los eventos de Messenger pasan a llevar:

    json
    "wame": {
      "seq": 42,
      "event_ms": 1760000000000,
      "received_at_ms": 1760000000420,
      "dispatched_at_ms": 1760000000437
    }
    • seq es un contador por conversación, asignado en el orden en que recibimos el evento de Meta. Ordenar por él reconstruye la secuencia, incluso con horarios iguales.
    • event_ms es la hora del evento según Meta, en milisegundos; received_at_ms, cuando entró aquí; dispatched_at_ms, cuando salió. Del primero al segundo es latencia de Meta; del segundo al tercero, nuestra.

    El bloque es aditivo: ningún campo existente cambió. Por ahora solo en eventos de Messenger.

    En el mismo lote, GET /messenger/webhook-fields muestra qué campos de webhook suscribe tu Página y POST en la misma ruta suscribe los que faltan — eso explica los acuses de entrega, de lectura o las reacciones que nunca llegan.