Webhooks
En vez de preguntar cada rato si un documento ya está listo, istmobot te avisa. Registras una URL en Panel → Webhooks y recibes un POST firmado por cada evento.
Flujo típico: validar un pago Yappy
- 1 Tu cliente te manda la captura. La guardas en tu base con tu propio id (por ejemplo, el número de pedido).
- 2 La envías a istmobot con ese id en
referencia. Respuesta inmediata202: quedó en cola. - 3 Segundos después recibes
documento.listoconvalidado: true|falsey la mismareferencia. Actualizas tu registro.
curl -X POST https://api.istmobot.com/v1/yappy \ -H "Authorization: Bearer ib_live_..." \ -F "file=@captura.jpg" \ -F "referencia=PEDIDO-4821"
Eventos
| Evento | Cuándo | Datos principales |
|---|---|---|
documento.listo | Un documento enviado por API o panel terminó de procesarse | id, solucion, referencia, validado, resultado |
documento.error | No se pudo procesar (imagen ilegible, sin créditos) | id, referencia, error |
yappy.pago_recibido | Se registró un nuevo pago Yappy recibido por tu negocio | confirmacion, monto, emisor_nombre, emisor_telefono, fecha, mensaje |
Cuerpo del POST
{ "id": "5f1c…", "type": "documento.listo", "created_at": "2026-09-18T20:55:11.000Z", "data": { "id": "a9e5223e-…", "solucion": "yappy", "referencia": "PEDIDO-4821", "estado": "listo", "validado": true, "resultado": { "monto": 10, "referencia": "LQUXS-92132982", "emisor": { "nombre": "Euribiades Avila" }, "validacion": { "encontrado": true, "criterio": "confirmacion", "pago": { "confirmacion": "LQUXS-92132982", "monto": 10 } } }, "request_id": "a66b…" } }
Verificar la firma
Cada POST lleva X-Istmobot-Signature: t=<unix>,v1=<hmac>. El HMAC es SHA-256 con tu secreto (whsec_…, se muestra una sola vez al crear el webhook) sobre la cadena {t}.{cuerpo crudo}. Rechaza si no coincide o si t tiene más de 5 minutos.
// Node / Next.js route handler
import { createHmac, timingSafeEqual } from "node:crypto";
export async function POST(req: Request) {
const body = await req.text(); // crudo, sin parsear
const sig = Object.fromEntries(req.headers.get("x-istmobot-signature")!.split(",").map((p) => p.split("=")));
const esperado = createHmac("sha256", process.env.ISTMOBOT_WEBHOOK_SECRET!).update(`${sig.t}.${body}`).digest("hex");
const ok = esperado.length === sig.v1.length && timingSafeEqual(Buffer.from(esperado), Buffer.from(sig.v1));
if (!ok || Math.abs(Date.now() / 1000 - Number(sig.t)) > 300) return new Response("firma inválida", { status: 401 });
const evento = JSON.parse(body);
if (evento.type === "documento.listo" && evento.data.solucion === "yappy") {
await db.pedidos.update(evento.data.referencia, { pago_validado: evento.data.validado });
}
return new Response("ok"); // responde 2xx rápido; procesa en segundo plano si tardas
}Reintentos. Si tu endpoint no responde 2xx en 8 s, reintentamos a 1 min, 5 min, 30 min, 2 h y 12 h. Cada intento se ve en Panel → Webhooks → Entregas. Los eventos pueden llegar más de una vez: usa
id del evento para deduplicar.
istmobot