Volver al blog
Desarrolladores

Consultar el estado de un mensaje de WhatsApp: GET /messages/:id en Waspy

GET /api/v2/messages/:id, con scope messages:read, lee status y waMessageId. En el 201 de queued, waMessageId es null. El webhook message.status_changed es el camino; el GET es el polling de 1 a 2 segundos.

· 11 min
Consultar el estado de un mensaje de WhatsApp: GET /messages/:id en Waspy

Respuesta corta: el estado de un mensaje que ya encolaste se lee con GET https://api.waspytech.com/api/v2/messages/:id (scope messages:read). El :id es el UUID de data.id del 201, no el wamid de Meta. En ese 201, status es queued y waMessageId es null. Para enterarte de sent, delivered, read o failed sin preguntar, suscribite a message.status_changed.

La página del recurso está en messages. El ciclo, en estados de mensajes. El sobre del webhook, en eventos. El significado de cada estado y de los errorCode está en estados en la API. clientRef está en reconciliar con tu ERP. La clave entra en Scale y Enterprise: Planes y la API.

queued, y el wamid que todavía no existe

POST /api/v2/messages responde 201 enseguida. Waspy guardó el mensaje y lo encoló. Meta todavía no lo tiene, así que waMessageId viene null. Guardá data.id.

EstadoQué pasówaMessageId
queuedAceptado y encolado. Todavía no es un envío de Metanull en el 201
sentLlegó a los servidores de MetaEl wamid ya debería estar
deliveredLlegó al teléfonoSigue el mismo wamid
readLa persona lo leyó (tilde azul, si tiene las confirmaciones activas)Sigue el mismo wamid
failedNo se entregó. El motivo va en errorCode y errorMessagePuede haber quedado en null
La documentación recomienda dos formas de salir de queued:
  1. El webhook message.status_changed. Cuando pasa a sent, el payload trae waMessageId. Es el camino que la propia página marca como confiable.
  2. Un GET a los 1 o 2 segundos, con el UUID del 201.

El GET

curl -sS "https://api.waspytech.com/api/v2/messages/MSG_UUID" \
  -H "Authorization: Bearer $WASPY_API_KEY"

Scope: messages:read. El 200 trae status, waMessageId, clientRef, errorCode, errorMessage, direction, type, content, conversationId y createdAt, más meta.requestId.

RespuestaCuándo
200El UUID es de un mensaje de esta cuenta
400 VALIDATION_ERROREl path no es un UUID (por ejemplo un wamid)
404 MESSAGE_NOT_FOUNDNo hay un mensaje con ese id en la cuenta
403A la clave le falta messages:read
Este GET no cambia el estado y no le escribe a Meta. Releerlo no gasta un mensaje de servicio. Cada request sí cuenta para el cupo de la API: 120 por minuto por cuenta, compartidas por todas las claves. El 429 y el Retry-After están en rate limits y reintentos.

Cuándo consultar y cuándo esperar el webhook

SituaciónQué hacer
Producción, muchos envíosWebhook message.status_changed. No hagas un GET por cada tick
Acabás de recibir el 201 y todavía no tenés webhookUn GET /messages/:id a los 1 o 2 segundos, como dice la doc
Sigue en queuedOtro GET más tarde, con espera. No un loop cada fracción de segundo
failedLeé errorCode. No reintentes el GET esperando que se arregle solo
Lote (POST /messages/batch, 202)El mismo message.id de cada ítem queued, o el clientRef en el webhook
El alta de la suscripción está en gestionar webhooks. El payload trae previousStatus, newStatus, waMessageId, clientRef, errorCode y errorMessage.

Los eventos pueden llegar fuera de orden. Por cada id o clientRef, quedate con el estado más avanzado: read por encima de delivered, delivered por encima de sent. La página de eventos trata failed como terminal. El caso en que un error de Meta se reintenta y el mensaje sigue en queued está explicado en estados de mensajes: no lo redescubras acá.

clientRef vuelve. El Idempotency-Key, no

clientRef es un string opaco de hasta 256 caracteres que mandás en el POST (un número de pedido, un id de Tiendanube). Vuelve igual en el GET y en cada message.status_changed. Si no lo mandaste, es null.

El header Idempotency-Key es otra cosa, y solo del POST /messages: si repetís ese POST con la misma clave, Waspy devuelve la respuesta guardada y no encola otro mensaje. El GET no lee ese header. Mandarlo en la consulta no deduplica nada y no cambia el 200. Reintentar el GET es seguro: no crea un segundo WhatsApp.

POST /messages/:waMessageId/read no es este GET. Marca un entrante como leído y usa scope conversations:write. No te dice si tu saliente está delivered.

Qué no hacer

  • No uses el wamid como :id de este GET. Todavía es null en el 201, y cuando existe no es un UUID.
  • No armes un poll cada 200 ms. La doc habla de 1 o 2 segundos, y el cupo es de la cuenta entera.
  • No esperes que el Idempotency-Key del POST se aplique a la lectura.
  • No des el pedido por entregado con el 201. queued quiere decir encolado.

El mensaje, cuando Meta lo entrega, se cobra según la categoría. En Argentina, desde el 1 de octubre de 2026, un marketing sale alrededor de ARS 89,56 (US$0,0618). Un mensaje de servicio entra en las 1.000 por número y por mes; desde el siguiente, alrededor de ARS 37,68 (US$0,026). Un failed no es un mensaje entregado. La rate card es la fuente. Diez días sin tarjeta, en el registro.

Tu equipo atendiendo por WhatsApp en minutos

CRM facil pero potente. En 10 minutos tenes a tu equipo trabajando — no necesitas hablar con nadie.