Guía de instalación: usando el Webhook

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.

1. Registre la URL de su webhook

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.

2. Reciba las notificaciones

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.

3. Estados de una 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.

4. Verificación de firma

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)
  );
}

5. Alternativa: consultar el estado directamente

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.