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.
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.
| Estado | Qué pasó | waMessageId |
|---|---|---|
queued | Aceptado y encolado. Todavía no es un envío de Meta | null en el 201 |
sent | Llegó a los servidores de Meta | El wamid ya debería estar |
delivered | Llegó al teléfono | Sigue el mismo wamid |
read | La persona lo leyó (tilde azul, si tiene las confirmaciones activas) | Sigue el mismo wamid |
failed | No se entregó. El motivo va en errorCode y errorMessage | Puede haber quedado en null |
queued:
- El webhook
message.status_changed. Cuando pasa asent, el payload traewaMessageId. Es el camino que la propia página marca como confiable. - 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.
| Respuesta | Cuándo |
|---|---|
| 200 | El UUID es de un mensaje de esta cuenta |
400 VALIDATION_ERROR | El path no es un UUID (por ejemplo un wamid) |
404 MESSAGE_NOT_FOUND | No hay un mensaje con ese id en la cuenta |
| 403 | A la clave le falta messages:read |
Retry-After están en rate limits y reintentos.
Cuándo consultar y cuándo esperar el webhook
| Situación | Qué hacer |
|---|---|
| Producción, muchos envíos | Webhook message.status_changed. No hagas un GET por cada tick |
| Acabás de recibir el 201 y todavía no tenés webhook | Un GET /messages/:id a los 1 o 2 segundos, como dice la doc |
Sigue en queued | Otro GET más tarde, con espera. No un loop cada fracción de segundo |
failed | Leé 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 |
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
wamidcomo:idde este GET. Todavía esnullen 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-Keydel POST se aplique a la lectura. - No des el pedido por entregado con el 201.
queuedquiere 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.
