Skip to Content
Documentación de integración del API de Seif. ¿Dudas? soporte@pagosripei.com
EndpointsWebhooks

Webhooks

Los webhooks le avisan a tu servidor, en tiempo real, cuando algo ocurre: un cobro aprobado, una tarjeta guardada, una sesión que expiró. Es la forma recomendada de reaccionar a los pagos (mejor que hacer polling).


Eventos disponibles

EventoCuándo se emite
charge.approvedUn cobro fue aprobado.
charge.declinedUn cobro fue rechazado por el banco/tarjeta.
charge.failedUn cobro no se pudo procesar.
card.storedSe almacenó una tarjeta tras un cobro aprobado.
card.deletedSe eliminó una tarjeta guardada.
session.otp_requestedLa sesión solicitó un OTP (flujos con segundo factor).
session.otp_confirmedEl OTP fue confirmado.
session.expiredLa sesión expiró sin pagarse.

Registrar un endpoint

POST /v1/webhooks/endpoints

Autenticación: clave secreta (Authorization: Bearer sk_…).

CampoTipoDescripción
urlstring (https)A dónde Seif enviará los eventos. Debe ser https.
enabledEventsstring[]Eventos a recibir. Omítelo o envía [] para recibir todos.
descriptionstringNota interna (opcional).
curl -X POST https://api.seif.pagosripei.com/v1/webhooks/endpoints \ -H "Authorization: Bearer sk_test_tu_clave" \ -H "Content-Type: application/json" \ -d '{ "url": "https://api.mitienda.com/seif/webhooks", "enabledEvents": ["charge.approved", "charge.declined", "charge.failed"] }'

La respuesta incluye un secret (whsec_…), mostrado una sola vez. Guárdalo: con él verificas la firma de cada evento.


Formato del evento

Cada entrega es un POST con este cuerpo:

{ "id": "evt_1a2b3c...", "type": "charge.approved", "createdAt": "2026-06-09T18:05:12.000Z", "env": "production", "data": { "transactionReference": "txn_2nFp9Zk", "sessionReference": "cs_8sKd2pQ1Aa", "amountMinor": 105000, "currency": "VES", "status": "approved" } }

Cuerpo de data según el evento:

Eventodata
charge.*{ transactionReference, sessionReference, amountMinor, currency, status }
card.stored{ seifToken, brand, lastFour, customerRef }
session.expired{ sessionReference }

Verificar la firma

Cada entrega trae el header Seif-Signature:

Seif-Signature: t=1717954512,v1=5f8e...c3

Recalcula HMAC-SHA256 sobre `${t}.${cuerpoCrudo}` con tu secret (whsec_…) y compara con v1. Verifica además que t sea reciente para rechazar reenvíos.

import crypto from 'crypto'; function verifySeifWebhook(rawBody, header, secret) { const parts = Object.fromEntries(header.split(',').map((p) => p.split('='))); const expected = crypto .createHmac('sha256', secret) .update(`${parts.t}.${rawBody}`, 'utf8') .digest('hex'); const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1)); const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300; // 5 min return ok && fresh; }

Verifica la firma usando el cuerpo crudo (sin parsear). Si tu framework parsea el JSON antes, re-serializar cambiará los bytes y la firma no coincidirá.


Entregas y reintentos

  • Responde 2xx rápido (idealmente < 5 s). Cualquier otra respuesta se considera fallida.
  • Seif reintenta hasta 5 veces con backoff exponencial.
  • Puedes consultar el historial de entregas y reintentar manualmente:
GET /v1/webhooks/deliveries GET /v1/webhooks/deliveries/{id} POST /v1/webhooks/deliveries/{id}/retry

Diseña tu endpoint para ser idempotente: usa el id del evento (evt_…) para no procesar dos veces el mismo evento si llega repetido tras un reintento.

Last updated on