Documentation Index
Fetch the complete documentation index at: https://docs.waspytech.com/llms.txt
Use this file to discover all available pages before exploring further.
POST /messages
Enviar un mensaje de WhatsApp. Soporta texto, imagen, video, audio, documento, template e interactivos.
Scope requerido: messages:write
Body
| Campo | Tipo | Requerido | Descripción |
|---|
phoneNumberId | string (UUID) | Sí | ID del canal (de GET /channels) |
to | string | Sí | Número del destinatario en formato E.164 (+5491126032641) |
type | string | Sí | text, image, video, audio, document, template, interactive |
text | object | Si type=text | { body: string, preview_url?: boolean } |
image | object | Si type=image | { link?: string, id?: string, caption?: string } |
video | object | Si type=video | { link?: string, id?: string, caption?: string } |
audio | object | Si type=audio | { link?: string, id?: string } |
document | object | Si type=document | { link?: string, id?: string, filename?: string, caption?: string } |
template | object | Si type=template | { name: string, language: { code: string }, components?: array } |
Enviar texto
curl -X POST https://api.waspytech.com/api/v2/messages \
-H "Authorization: Bearer wspy_..." \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "channel-uuid",
"to": "+5491126032641",
"type": "text",
"text": { "body": "Hola! Tu pedido fue despachado." }
}'
Los mensajes de texto libre requieren una ventana de servicio activa (24hs desde el último mensaje del contacto). Si la ventana expiró, usá un template. Ver Ventana de servicio.
Enviar template
curl -X POST https://api.waspytech.com/api/v2/messages \
-H "Authorization: Bearer wspy_..." \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "channel-uuid",
"to": "+5491126032641",
"type": "template",
"template": {
"name": "confirmacion_pedido",
"language": { "code": "es_AR" },
"components": [
{
"type": "body",
"parameters": [
{ "type": "text", "text": "María" },
{ "type": "text", "text": "#1847" }
]
}
]
}
}'
Enviar imagen
curl -X POST https://api.waspytech.com/api/v2/messages \
-H "Authorization: Bearer wspy_..." \
-H "Content-Type: application/json" \
-d '{
"phoneNumberId": "channel-uuid",
"to": "+5491126032641",
"type": "image",
"image": { "link": "https://ejemplo.com/producto.jpg", "caption": "Vista frontal" }
}'
Response 201
{
"data": {
"id": "msg-uuid",
"conversationId": "conv-uuid",
"direction": "outbound",
"type": "text",
"status": "queued",
"waMessageId": null,
"createdAt": "2026-04-13T15:00:00.000Z"
},
"meta": { "requestId": "..." }
}
waMessageId es null en el response inicial. El envío a Meta es asíncrono — status: "queued" significa que aceptamos la request y la encolamos. Para obtener el waMessageId real (el wamid.HBgL... de Meta) tenés dos opciones:
- Recomendado: suscribite al webhook
message.status_changed. Cuando el status pasa a sent, el payload trae waMessageId poblado. Es la forma confiable.
- Polling:
GET /messages/{data.id} después de 1-2 segundos.
Para correlacionar tu mensaje con el de Meta inmediatamente, guardá el data.id (UUID interno) que sí está disponible al instante.
Idempotencia
Incluí el header Idempotency-Key para evitar envíos duplicados. Ver Idempotencia.
curl -X POST https://api.waspytech.com/api/v2/messages \
-H "Authorization: Bearer wspy_..." \
-H "Idempotency-Key: pedido-1847-confirmacion" \
-H "Content-Type: application/json" \
-d '{ ... }'
Errores frecuentes
| Código | Descripción |
|---|
SERVICE_WINDOW_EXPIRED | La ventana de 24hs expiró, usá un template |
INVALID_CHANNEL | El canal no existe o no pertenece a tu cuenta |
CHANNEL_NOT_CONNECTED | El canal no está conectado |
INVALID_MESSAGE_TYPE | Tipo de mensaje no válido |
INVALID_PHONE | Número de teléfono con formato inválido |
Comportamiento
- Si el contacto no existe, se crea automáticamente con el número.
- Si no hay conversación previa, se crea una nueva.
- El mensaje se encola y se envía de forma asíncrona. El status inicial es
queued.
- Consultá el estado final con
GET /messages/:id.
GET /messages/:id
Consultar un mensaje por ID. Útil para verificar el estado de envío.
Scope requerido: messages:read
curl https://api.waspytech.com/api/v2/messages/MSG_ID \
-H "Authorization: Bearer wspy_..."
Response 200
{
"data": {
"id": "msg-uuid",
"conversationId": "conv-uuid",
"direction": "outbound",
"type": "text",
"content": { "text": "Hola! Tu pedido fue despachado." },
"status": "delivered",
"waMessageId": "wamid.HBgLNT...",
"errorCode": null,
"errorMessage": null,
"createdAt": "2026-04-13T15:00:00.000Z"
},
"meta": { "requestId": "..." }
}
Para entender los estados posibles, ver Estados de mensajes.
POST /messages/:waMessageId/read
Marcar un mensaje entrante como leído por su waMessageId (el mismo que llega en el webhook message.received). Conveniente cuando tenés a mano el waMessageId en lugar del conversationId.
Scope requerido: conversations:write
curl -X POST https://api.waspytech.com/api/v2/messages/wamid.HBgLNT.../read \
-H "Authorization: Bearer wspy_..."
Equivalente a POST /conversations/:id/read — manda el read receipt a Meta y resetea el unreadCount de la conversación padre.
{
"data": {
"conversationId": "conv-uuid",
"markedMessageId": "wamid.HBgLNT...",
"deliveredToMeta": true
},
"meta": { "requestId": "..." }
}
404 si el waMessageId no existe o no es inbound.