Webhooks de eventos, firmados
Siete eventos, un endpoint por cuenta, y cada entrega va firmada como las de Stripe. Cada carga útil dice en qué número pasó, así que una sola URL atiende todos los números que tengas.
Regístralo una vez
import { Whatsapi } from "@whatsapi.sh/sdk";
const wa = new Whatsapi({ apiKey: "wa_your_key" });
const data = await wa.setWebhook({ url: "https://api.yourapp.com/webhooks/whatsapp" });{
"data": {
"secret": "whsec_…", // shown ONCE, store it
"record": { "url": "…", "events": ["message.created", "…"], "enabled": true }
}
}Eventos: message.created, message.sent, message.failed, message.status, number.connected, number.disconnected, number.logged_out, number.history_synced. Los dos del medio son el desenlace de un mensaje que esperó en la cola de envío. El último llega una vez por vinculación, cuando el teléfono terminó de enviar sus chats antiguos o pasó 10 minutos sin enviar nada. Para rotar el secreto, guarda el endpoint con "rotateSecret": true.
Verifica la firma
Cada entrega lleva x-whatsapi-signature: t=<unix>,v1=<hmac>, un HMAC-SHA256 de <t>.<body> con tu secreto. Verifícalo antes de confiar en nada:
import { verifyWebhook, WebhookSignatureError } from "@whatsapi.sh/sdk";
// Signature, replay window and constant-time compare, in one call. Anything
// that does not check out throws WebhookSignatureError. Answer 400.
const event = await verifyWebhook({
payload: rawBody, // the raw bytes, not the parsed body
signature: req.header("x-whatsapi-signature"),
secret: process.env.WHATSAPI_WEBHOOK_SECRET,
});Espera reintentos y deduplica
Cada evento tiene hasta 5 intentos de entrega. Reintentamos si no llega una respuesta o si recibimos un 5xx, 408, 425 o 429. Entre intentos esperamos 30, 60, 120 y 240 segundos. Si Retry-After pide más tiempo, ampliamos la espera hasta un máximo de 1 hora por reintento. Los demás códigos 4xx y las redirecciones terminan la entrega sin reintentos. Registra la URL final, sin redirecciones. Todos los intentos llevan el mismo id x-whatsapi-delivery. Úsalo para no procesar el evento dos veces. Tras 10 entregas fallidas seguidas, desactivamos el endpoint. Los intentos que aún se van a repetir no cuentan para ese límite. Guarda el endpoint corregido o envía una prueba exitosa para reactivarlo. POST /v1/webhooks/test envía una sola prueba y muestra qué respondió tu endpoint.
Lee el historial de un chat
Si tu endpoint estuvo caído, o quieres contexto antes de responder, lee el chat directamente. Los mensajes llegan del más nuevo al más viejo, cada uno con el mismo formato que message.created. Un número guarda los últimos 100 mensajes de cada chat, salvo que cambies historyPerChat con PATCH /v1/numbers/:id. Con 0 no se guarda nada.
import { Whatsapi } from "@whatsapi.sh/sdk";
const wa = new Whatsapi({ apiKey: "wa_your_key" });
const data = await wa.getChatHistory({ chat: "+5511987654321" });¿Todavía no sabes qué chats hay? GET /v1/chats lista los chats que guardó un número, del más reciente al más antiguo. Después, lee cada uno como arriba.
import { Whatsapi } from "@whatsapi.sh/sdk";
const wa = new Whatsapi({ apiKey: "wa_your_key" });
const data = await wa.listChats();