Resolver una conversación de WhatsApp por teléfono con la API de Waspy
GET /api/v2/conversations/resolve acepta un celular argentino en +549 o en 5411. No trae serviceWindowExpiresAt: esa fecha está en GET /conversations/:id. by-phone devuelve solo el chat más reciente.
Respuesta corta: el ERP tiene +54911… y no tiene el UUID del chat. GET https://api.waspytech.com/api/v2/conversations/resolve?phone= lo busca dentro de tu cuenta. El scope es conversations:read. Esa respuesta no trae serviceWindowExpiresAt. Para saber si la ventana de 24 horas sigue abierta, el paso siguiente es GET /api/v2/conversations/:id.
La referencia está en conversations. El deep link del panel, el PATCH (open / closed) y el caso del 15 en el medio están en abrir el chat desde el CRM. Esta nota es el teléfono argentino y la ventana. El listado de la bandeja está en conversaciones por API.
Qué pedido, según lo que tenés
| Tenés | Pedido | Qué vuelve |
|---|---|---|
| Teléfono, y puede haber Instagram o más de una línea | GET /conversations/resolve | conversationId, match, alternatives, phoneHasWhatsApp |
| Solo el celular, un chat de WhatsApp | GET /conversations/by-phone/:phone | conversationId, contactName, contactPhone, o data: null |
| El UUID | GET /conversations/:id | El chat, incluido serviceWindowExpiresAt |
conversations:read. Ninguno crea el hilo. La API pública está en Scale y Enterprise: Planes y la API.
El +549
Un celular de Argentina, para WhatsApp, va en E.164 con el 9 móvil: +549 + código de área + abonado, sin el 0 y sin el 15. El ejemplo de la documentación es +5491126032641.
resolve tolera espacios, guiones y el +. Arma la familia 54 / 549:
| Mandás | También busca |
|---|---|
+5491140796637 o 5491140796637 | La variante sin el 9 (541140796637), con + y sin + |
+541126032641 (sin el 9) | La variante con 9 (5491126032641) |
| Un local de 8 dígitos o más, sin 54 | 54 + dígitos y 549 + dígitos |
resolve puede matchear los últimos 8 dígitos. Eso atrapa un alta vieja. También puede juntar dos abonados distintos que terminan igual: mirá match.contactPhone antes de escribirle a esa persona.
curl -sS --get "https://api.waspytech.com/api/v2/conversations/resolve" \
--data-urlencode "phone=+5491140796637" \
--data-urlencode "channel=whatsapp" \
--data-urlencode "line=28392709" \
-H "Authorization: Bearer $WASPY_API_KEY"
line y channel no filtran. Si la persona tiene un chat de WhatsApp y otro de Instagram, ordenan cuál vuelve en conversationId. El resto queda en alternatives. line acepta los últimos dígitos de la línea de la tienda, el id de Meta o el UUID del número en Waspy. Menos de 6 dígitos no se usa como línea.
La respuesta 200:
{
"data": {
"conversationId": "64ed37aa-5506-44a6-b8d6-f25a2936255d",
"match": {
"conversationId": "64ed37aa-5506-44a6-b8d6-f25a2936255d",
"channel": "whatsapp",
"contactName": "María",
"contactPhone": "+5491140796637",
"contactUsername": null,
"contactEmail": null,
"lastMessageAt": "2026-04-14T14:32:00.000Z",
"lineLabel": "Ventas"
},
"alternatives": [],
"phoneHasWhatsApp": true
},
"meta": { "requestId": "..." }
}
El ejemplo de la página de docs no muestra phoneHasWhatsApp. El schema de la ruta lo exige. Es true solo si algún chat devuelto es de WhatsApp y el teléfono del contacto es una variante 54/549 del parámetro. Un match por Instagram, por email o por los últimos 8 dígitos de otro número no alcanza.
Si no hay ninguno, conversationId y match son null y alternatives es []. Sigue siendo 200. En el CRM mostrá “todavía no hay chat”. El primer mensaje, si corresponde, es un POST /api/v2/messages con plantilla, como en enviar una plantilla.
Sin phone, sin ig y sin email, es 400 BAD_REQUEST. channel distinto de whatsapp, instagram o email también. Una clave con scopes y sin conversations:read es 403 FORBIDDEN.
by-phone es más chico. El + en el path va como %2B. No busca Instagram, no trae alternatives y, si no hay chat, data es null con 200.
curl -sS "https://api.waspytech.com/api/v2/conversations/by-phone/%2B5491140796637" \
-H "Authorization: Bearer $WASPY_API_KEY"
El 15 viejo, metido después del código de área (11 15 …), no se recorta en esa ruta. Pasá el +549 canónico. El detalle del 15 está en la nota del CRM.
La ventana: el segundo GET
serviceWindowExpiresAt no está en resolve ni en by-phone. Está en el detalle:
curl -sS "https://api.waspytech.com/api/v2/conversations/CONV_ID" \
-H "Authorization: Bearer $WASPY_API_KEY"
El 200 incluye serviceWindowExpiresAt (fecha ISO o null), lastMessageAt, status, phoneNumberId y contact (name, phoneNumber, email). El mismo campo viene en cada ítem de GET /api/v2/conversations.
serviceWindowExpiresAt | Qué podés mandar |
|---|---|
| Una fecha en el futuro | Texto, foto, audio o documento: es mensaje de servicio |
Una fecha ya pasada, o null | No cuentes con texto libre. El POST de texto responde 403 SERVICE_WINDOW_EXPIRED |
Este GET no manda nada y no gasta ese cupo. Lo que gasta es el mensaje que después encolás.
Lo que el teléfono no alcanza a decir
- No uses
phoneHasWhatsApppara “ver si el número existe en WhatsApp”. Dice si en tu cuenta ya hay un chat. - Una API key limitada a ciertas líneas solo ve esas líneas. Un token de usuario respeta la visibilidad del inbox: si esa persona no puede abrir el chat, no aparece.
- La página de scopes lista
GET /conversationsyGET /conversations/:idparaconversations:read. No nombraresolveniby-phone. Las dos rutas igual exigen ese scope. - Leer y resolver no es un mensaje entregado. Meta no lo cobra.
Diez días sin tarjeta, en el registro.
