Estados de mensaje

Saber qué pasó con cada mensaje que mandaste —en cola, enviado, entregado, leído o falló—, por el aviso message.status_changed o consultando el mensaje.

Sabé qué pasó con cada mensaje que mandaste: los de tu clave y también los del chat, las automatizaciones y los asistentes de IA. Hay dos caminos, que dan lo mismo: el aviso message.status_changed, que te llega solo, y Ver un mensaje, que consultás cuando querés.

Los estados

statusQué significa
queuedRegistrado y en cola: está por salir. En cola no es enviado. Solo aparece al consultar el mensaje; no genera aviso.
sentEl proveedor aceptó el mensaje. Aceptado no es entregado.
deliveredLlegó al teléfono del contacto.
readEl contacto lo abrió (si tiene activadas las confirmaciones de lectura).
failedNo salió o no se pudo entregar. Viene con error (abajo).
nullEl resultado no se conoce: el proveedor no confirmó ni rechazó el envío, o el envío se interrumpió. Puede haber llegado y no va a cambiar de estado.

Lo normal es queued → sent → delivered → read. Cada estado se informa una sola vez por mensaje y nunca uno que retroceda: si llegan varios avisos juntos se informa el más avanzado, y un aviso atrasado que no cambia el estado no genera evento.

Cuando falla

error trae code, title y reason, solo cuando status es failed:

  • Lo rechazó el proveedor: code es su código numérico y title su título (cualquiera de los dos puede ser null); reason es null.
  • Lo frenó Funnelchat antes de que saliera (solo en mensajes enviados con clave): reason trae el motivo, code es null y title es un texto llano en el idioma de la cuenta. No salió: reintentar es un intento nuevo y no lo duplica.
error.reasonQué hacer
device_unavailableReconectá el número en Funnelchat y mandá de nuevo.
insufficient_balanceRecargá tu billetera de WhatsApp.
window_closedMandá una plantilla aprobada.
recipient_unreachableRevisá el teléfono del contacto.
template_not_found, template_unresolved_placeholderCorregí la plantilla o sus variables.
not_queued, not_sentVolvé a intentarlo.

Más de una hora en queued: un mensaje cuyo envío no empezó dentro de la hora ya no sale. Pasada la hora sin resultado, su status es null, o failed con reason: "not_sent" si su envío llega tarde (y entonces sí te llega su aviso).

El aviso: message.status_changed

{
  "id": "evt_000000000000000000000014",
  "type": "message.status_changed",
  "version": 1,
  "occurred_at": "2026-10-01T12:00:00Z",
  "data": {
    "message_id": 1001,
    "contact_id": 2001,
    "device_id": 4521,
    "status": "failed",
    "previous_status": "sent",
    "error": { "code": 131047, "title": "Re-engagement message", "reason": null },
    "occurred_at": "2026-10-01T12:00:00Z",
    "client_reference": "pedido-1001"
  }
}
CampoQué es
message_idEl id del mensaje: el mismo id que devuelve el envío y el historial del contacto.
contact_id, device_idEl contacto y el número por el que salió (el mismo device_id con el que mandás).
statussent, delivered, read o failed.
previous_statusEl estado anterior. Es null si es el primer aviso del mensaje, si repite el estado que ya tenía o si no se pudo leer.
errorSolo cuando status es failed: code, title y reason (arriba).
occurred_atCuándo registró Funnelchat el estado, en UTC.
client_referenceLa referencia que mandaste al enviar, o null. Sirve para relacionar el aviso con tu envío aunque la llamada de envío no haya respondido.
  • Qué mensajes lo emiten: los que se mandan a un contacto desde el chat, una automatización o un asistente de IA, incluidos los de tu clave. No se emite para mensajes de difusiones ni para mensajes recibidos.
  • Un mensaje que no llegó a salir no tiene avisos, salvo uno enviado con clave: ese recibe un único aviso failed, con previous_status en null, su error.reason y su client_reference. Un mensaje con resultado desconocido (status null) no recibe aviso.
  • En cuentas con mucho tráfico se descartan los eventos que superan el límite de entrega por minuto de la cuenta. Si necesitás el estado de un mensaje concreto, consultalo.
  • El id del evento es el mismo en todos los reintentos de una entrega: si te llega dos veces, descartá el repetido por id.

Cómo suscribirte

Igual que a cualquier evento, con una suscripción que tenga tu URL y message.status_changed en events (Webhooks). Pedilo de forma explícita: es el único evento de mensajes que hay que nombrar siempre. Para elegirlo, la clave necesita webhooks:write y además conversations:read, el permiso de lectura de su área. El paso a paso está en Armá tu propio flujo.

El estado en el historial

El historial de un contacto trae el estado de cada mensaje en status, pero la especificación lo publica como un número, sin el nombre de cada valor. Para el estado con nombre, consultá Ver un mensaje con el id, o usá el aviso.

Probalo acá

El historial de un contacto, con tu clave. Es una lectura: no manda nada.

Listar los mensajes de un contacto

GET
/contacts/{contactId}/messages

Permiso requerido: conversations:read

Autorización

http
headerAuthorizationBearer <clave>

Parámetros de la ruta

contactId*integer

Parámetros de consulta

cursor?string
updated_since?string
perPage?integer
Rango1 <= value <= 100
Por defecto25

Cuerpo de la respuesta

OK

application/json
  1. response
data*array<>
links*
meta*
curl -X GET "https://example.com/contacts/0/messages"
{  "data": [    {      "chat_id": "string",      "contact_id": 0,      "content": [],      "device_id": 0,      "error_code": "string",      "file": "string",      "forwarded": 0,      "group_id": 0,      "id": 0,      "origin": 0,      "origin_id": 0,      "own": 0,      "reference_message": "string",      "reference_message_uid": "string",      "is_quotable": true,      "status": 0,      "temporal_uuid": "string",      "text": "string",      "time": "string",      "type": 0,      "uid": "string",      "info": [],      "user_id": 0,      "deleted_at": "string",      "deleted_scope": "string",      "poll_results": "string",      "event_rsvps": "string",      "form_answers": "string",      "reactions": [        null      ],      "file_original_name": "string",      "client_reference": "string"    }  ],  "links": {    "first": "string",    "last": "string",    "prev": "string",    "next": "string"  },  "meta": {    "path": "string",    "per_page": 0,    "next_cursor": "string",    "prev_cursor": "string"  }}

En esta página