El webhook es la dirección opuesta a las credenciales de las otras 2 guías: aquí es VerySinple quien le notifica a su tienda cuando el estado de una orden cambia.
Desde "Integración con tienda", registre la URL de su tienda que recibirá las notificaciones. Debe ser https:// — VerySinple rechaza cualquier otra URL. Al registrarla (o rotarla) recibe un secreto, mostrado una sola vez, usado para firmar cada entrega.
POST <su URL de webhook>
Content-Type: application/json
X-SinpeGuard-Event: ORDER_STATUS_CHANGED
X-SinpeGuard-Signature: sha256=<hex>
Idempotency-Key: <id estable, el mismo en reintentos>
{
"orderId": "su-orden-123",
"status": "ACCEPTED",
"amount": "7900.00",
"currency": "CRC",
"reference": "REF123",
"reconciledAt": "2026-08-25T14:32:00Z"
}
reference puede venir null si aún no hay un pago asociado a la orden.
Solo existen estos 4 — no hay un estado separado PAID/RECONCILED ni un estado EXPIRED por expiración automática.
PENDINGEstado inicial — aún no se ha encontrado un pago SINPE que coincida.REVIEWCoincidencia ambigua — requiere resolución manual desde el panel de VerySinple.ACCEPTEDTerminal. Coincidencia confirmada — este es el estado que indica que la orden fue pagada y conciliada.REJECTEDTerminal. Rechazada manualmente, o no se encontró ningún candidato de pago.Cada entrega incluye una firma HMAC-SHA256 calculada sobre el cuerpo JSON crudo (los bytes exactos recibidos, antes de cualquier parseo), usando como llave el secreto del webhook. El header es literalmente sha256= seguido del hash en hexadecimal.
const crypto = require('crypto');
function verifySignature(rawBody, signatureHeader, webhookSecret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', webhookSecret)
.update(rawBody) // el buffer/string crudo, sin parsear
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}
express.raw() en Express antes del parseo JSON).Idempotency-Key.Sin depender del webhook, o como respaldo ante una entrega perdida:
GET https://api.sinpeguard.com/v1/store/orders/{clientOrderId}
Authorization: Bearer {keyId}.{secret}
Devuelve el mismo contenido que el webhook, sin el sobre de evento. Solo puede consultar órdenes de su propia tienda.