Webhooks de Collections
Verifica eventos de checkout y confirma compras sólo después del éxito de pago autorizado.
Los webhooks notifican a tu backend los resultados de enlaces de pago y Cart Checkout. Una redirección no prueba un pago: el navegador puede cerrarse o un medio asíncrono terminar más tarde.
Eventos principales
| Evento | Significado | Confirmar compra |
|---|---|---|
checkout_session_completed | Terminó el flujo; el pago puede seguir processing | No |
checkout_session_expired | La sesión ya no puede usarse | No |
purchase_succeeded | La compra alcanzó el éxito de pago autorizado | Sí, después de verificar y deduplicar |
purchase_succeeded puede incluir checkoutSession.id. Úsalo para reconciliar sesión, clientReferenceId, factura, pago, suscripción y carrito original.
Configurar y recibir
Configura un endpoint en los ajustes de integración y verifica su activación para la empresa y entorno elegidos. Necesitas acceso a esa configuración y un receptor en tu servidor.
- Pharos guarda el estado comercial y envía el evento JSON al endpoint configurado.
- Tu servidor lee el cuerpo original y verifica
x-pharos-signaturecon el secreto de firma. - Interpreta sólo el evento verificado y comprueba si ya procesaste su
eventIdoidempotencyKey. - Registra la identidad y ejecuta la acción comercial de forma atómica o mediante un flujo idempotente equivalente.
- Responde exitosamente sólo después de aceptar la entrega. Las entregas fallidas pueden reintentarse.
Verificar la firma
Pharos firma los bytes exactos del cuerpo con HMAC SHA-256 y envía x-pharos-signature: sha256=.... Calcula la firma antes de parsear JSON y compara con una función de tiempo constante:
import { createHmac, timingSafeEqual } from 'node:crypto'
export function verifyPharosSignature(
rawBody: Buffer,
signatureHeader: string,
signingSecret: string,
) {
const received = signatureHeader.replace(/^sha256=/, '')
const expected = createHmac('sha256', signingSecret)
.update(rawBody)
.digest('hex')
const receivedBuffer = Buffer.from(received, 'hex')
const expectedBuffer = Buffer.from(expected, 'hex')
return receivedBuffer.length === expectedBuffer.length
&& timingSafeEqual(receivedBuffer, expectedBuffer)
}Rechaza firmas ausentes, malformadas o inválidas. No verifiques un JSON serializado de nuevo: espacios y orden de claves pueden cambiar los bytes.
Evitar efectos duplicados
Trata las entregas como al menos una vez, no exactamente una vez. Guarda eventId o la idempotencyKey estable con una restricción única. Una entrega repetida debe responder éxito sin duplicar pedidos, acceso al servicio, emails ni otras acciones.
async function handleVerifiedEvent(event: PharosEvent) {
if (await events.has(event.eventId)) return
await database.transaction(async (tx) => {
await tx.events.insert({
eventId: event.eventId,
idempotencyKey: event.idempotencyKey,
})
if (event.eventKey === 'purchase_succeeded') {
await tx.orders.markFulfilled({
checkoutSessionId: event.payload.checkoutSession?.id,
})
}
})
}Este ejemplo es ilustrativo: adapta tipos, transacciones y almacenamiento a tu sistema. La identidad única debe proteger también frente a dos entregas concurrentes.
Medios asíncronos
Transferencias, tickets, efectivo o redirecciones pueden completarse después del checkout. Una sesión puede estar complete con paymentStatus=processing. Mantén el pedido pendiente hasta recibir purchase_succeeded; no deduzcas éxito por tiempo transcurrido.
Si falla después, actualiza el pedido con el evento verificado correspondiente. Reutiliza la sesión sólo si su estado permite otro intento.
Historial y reintentos
Los endpoints deben usar HTTPS público, sin credenciales en la URL. Se rechazan destinos privados o inseguros y no se siguen redirecciones. La entrega tiene un plazo de diez segundos.
La entrega automática admite hasta ocho intentos en un máximo de 24 horas. Los reintentos conservan ID y cuerpo firmado. La configuración de integración enlaza al historial; un reintento manual afecta esa entrega y no reenvía el evento a email o analítica.
Las notificaciones comerciales requieren activación. Reconciliar pagos antiguos no envía automáticamente notificaciones históricas. Verifica activación y configuración antes de depender de eventos en producción.
Verificar y resolver problemas
- Prueba éxito inmediato y demorado, fallo, vencimiento y entregas duplicadas en Sandbox.
- Conserva el secreto fuera del código y usa la configuración compatible para rotarlo.
- Si falla la firma, comprueba cuerpo original, header y secreto antes de procesar.
- Si no llegan eventos, revisa activación, historial y respuesta de tu endpoint.
- Responde rápido y delega trabajo lento a un flujo idempotente; alerta por fallos repetidos.
- Guarda identificadores de evento y correlación sin registrar secretos ni datos sensibles de pago.