Volver al blog
Desarrolladores

Cómo gestionar webhooks de la API de Waspy (alta, firma, reintentos)

CRUD en /api/v2/webhooks: crear, listar, editar, borrar, probar, rotar el secret y reenviar. Un 2xx o un 3xx es entrega. El log pagina con cursor opaco. Scale y Enterprise.

· 12 min
Cómo gestionar webhooks de la API de Waspy (alta, firma, reintentos)

Respuesta corta: das de alta un webhook con POST https://api.waspytech.com/api/v2/webhooks, scope webhooks:write. Guardá el secret de esa respuesta: no vuelve a salir. Tu URL tiene que responder 2xx o 3xx en menos de 10 segundos. La firma va en X-Waspy-Signature. La API pública está en Scale y Enterprise.

La referencia está en webhooks, el modelo de entrega en introducción y la firma en seguridad. Cómo verificar el HMAC en Node y Python, sin repetir el algoritmo acá, está en verificar la firma.

Qué podés hacer

MétodoRutaScopePara qué
GET/api/v2/webhookswebhooks:readListar las del tenant
POST/api/v2/webhookswebhooks:writeCrear. El secret sale una vez
GET/api/v2/webhooks/:idwebhooks:readUna suscripción, sin secret
PATCH/api/v2/webhooks/:idwebhooks:writeurl, events, description, enabled, headers
DELETE/api/v2/webhooks/:idwebhooks:writeBorrar
POST/api/v2/webhooks/:id/testwebhooks:writeEvento sintético message.received
GET/api/v2/webhooks/:id/deliverieswebhooks:readLog de intentos, cursor opaco
POST/api/v2/webhooks/:id/rotate-secretwebhooks:writeSecret nuevo, el viejo muere ya
POST/api/v2/webhooks/:id/replay/:deliveryIdwebhooks:writeReencolar una entrega del log
Cada suscripción es del tenant de la API key. No ves webhooks de otra cuenta. La base de la API está en la página de la API y en qué es la API de WhatsApp.

Crear la suscripción

url tiene que ser HTTPS. La query string se conserva en cada entrega. events es un array con al menos uno de estos cuatro, los únicos que acepta el schema:

EventoCuándo
message.receivedEntra un mensaje
message.status_changedUn saliente pasa a sent, delivered, read o failed
conversation.createdSe crea una conversación
contact.createdSe crea un contacto
curl -sS -X POST https://api.waspytech.com/api/v2/webhooks \
  -H "Authorization: Bearer $WASPY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://tu-bot.example.com/webhook/waspy",
    "events": ["message.received", "message.status_changed"],
    "description": "CRM de pedidos"
  }'

La respuesta 201 trae data.secret (empieza con whsec_ en los ejemplos de la doc). Copialo a WASPY_WEBHOOK_SECRET antes de cerrar la terminal. GET de después no lo incluye.

headers es opcional: hasta 10 headers extra, nombre de hasta 256 caracteres y valor de hasta 1024, sin saltos de línea. Van en el primer intento, en los reintentos y en el test. No podés pisar Content-Type, Content-Length, Host, X-Waspy-Signature, X-Waspy-Webhook-Id, X-Waspy-Webhook-Event, X-Waspy-Webhook-Version, X-Waspy-Webhook-Attempt ni X-Waspy-First-Attempt-At. En los GET el valor vuelve enmascarado (**). En un PATCH, headers reemplaza el conjunto entero: null o {} los borra; si omitís el campo, quedan como estaban.

Qué cuenta como entrega

Tu URL respondeQué hace Waspy
2xxEntrega ok
Cualquier 3xxEntrega ok. Guarda ese status (un 302 queda como 302). No reintenta
4xx o 5xxFallo. Entra en los reintentos
Nada en 10 segundosFallo
Un Google Apps Script suele contestar 302 después de correr doPost. Eso es éxito. Si lo contáramos como error, el mismo evento se procesaría otra vez. Waspy no repite el POST contra Location. Si hay Location, puede hacer un GET solo para anotar qué devolvió el redirect, después de validar esa URL. Si ese GET falla, la entrega sigue contando como exitosa.

La misma regla vale para el test y para el replay.

Reintentos y apagado

Si falla, los intentos siguientes esperan así:

IntentoEspera antes
21 minuto
35 minutos
430 minutos
52 horas
Último12 horas
A las 10 fallas seguidas la suscripción queda enabled: false. PATCH con { "enabled": true } la reactiva y resetea el contador.

Respondé 200 enseguida y procesá el evento después. El body no cambia el resultado. Si la firma no cierra, un 401 deja el error asentado. El algoritmo (HMAC-SHA256 de t + . + body crudo, ventana de 5 minutos sobre t, edad del payload en X-Waspy-First-Attempt-At) está en verificar la firma y en la doc de seguridad.

Probar, leer el log y reenviar

POST /webhooks/:id/test encola un message.received de prueba. La respuesta trae samplePayload con la forma del sobre. Esas pruebas sí aparecen en GET /webhooks/:id/deliveries, y no actualizan lastDeliveryAt, lastDeliveryStatus ni consecutiveFailures. Para ver si pegó, consultá el log justo después.

curl -sS "https://api.waspytech.com/api/v2/webhooks/SUB_UUID/deliveries?status=failed&limit=20" \
  -H "Authorization: Bearer $WASPY_API_KEY"

meta.cursor es opaco y meta.hasMore dice si hay otra página. No armes el cursor: un valor fabricado responde 400 INVALID_CURSOR. Cómo está armada la paginación de toda la API está en page y cursor.

El id de cada fila es el deliveryId de POST /webhooks/:id/replay/:deliveryId. El replay no reenvía el body original guardado: la tabla guarda el hash, no el payload verbatim. Vuelve a disparar el mismo event con datos sintéticos. Tu handler tiene que ser idempotente sobre data.id. El catálogo de cada data está en eventos.

message.status_changed es el lugar donde vuelve el clientRef que mandaste al enviar. Ese recorrido está en reconciliar estados.

Quién tiene la API

La API REST con webhooks está en los planes Scale (US$150 por mes) y Enterprise. Starter y Growth atienden desde el panel, sin esta clave. Diez días de prueba, sin tarjeta, en el registro. El detalle de cada plan está en Planes.

Tu equipo atendiendo por WhatsApp en minutos

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