sequence y applicationId.
La envoltura
El cuerpo es idéntico byte por byte a través de cada entrega y reenvío del mismo evento. Todo lo que varía por intento de entrega — el ID de entrega, el contador de intentos, la marca de tiempo, la firma — vive en su lugar en los encabezados HTTP.
Eventos, entregas e intentos
Tres registros distintos están detrás de cada webhook que te llega, y cada uno lleva su propio identificador y sus propias marcas de tiempo. Mantenerlos claros es la clave para reconciliar las distintas marcas de tiempo y la lógica desequence que se explica a continuación.
La división sigue una sola regla: todo lo intrínseco al evento —
id, type, sequence, originalCreateDate, data — vive en el cuerpo y nunca cambia; todo lo que describe esta solicitud HTTP en particular — ID de entrega, número de intento, tipo de intento, marca de tiempo, firma — vive en los encabezados y se regenera en cada intento.
Los payloads llevan el cambio de estado, no el recurso completo
Los payloads de webhook contienen deliberadamente lo mínimo que necesitas para reaccionar: el ID del recurso y la transición depreviousStatus a status. No contienen el objeto del recurso completo.
La mayoría de las reacciones — enrutar según el nuevo estado, actualizar la fila en tu propia base de datos, notificar a tu equipo de operaciones — funcionan solo con el payload. Cuando necesites el recurso completo (criterios de verificación completos, detalles de cuenta bancaria, montos de transferencia), recupéralo del endpoint GET del recurso:
El campo sequence
sequence es un entero monotónicamente creciente delimitado a una única instancia de recurso — un contador por cliente, uno por transferencia, y así sucesivamente, identificado por data.id. Se asigna cuando se crea el evento y nunca cambia, por lo que refleja el orden real en que ocurrieron los cambios de estado incluso cuando las entregas llegan fuera de orden.
Debido a que el orden de entrega no está garantizado, usa sequence para protegerte contra actualizaciones obsoletas:
- Almacena el
sequencemás alto que hayas procesado por instancia de recurso — por ejemplo, una columnalastSphereSequenceen la fila del cliente en tu propia base de datos. - Cuando llegue un evento, compara su
sequencecon el valor almacenado para esedata.id. - Si
incoming.sequence <= stored.sequence, el evento es obsoleto o un duplicado — confirma con un2xxy omite la actualización. - De lo contrario, aplica la actualización y almacena el nuevo
sequence.
No asumas que los valores de sequence que recibes son contiguos. Si tu endpoint se suscribe a un subconjunto de los eventos de un recurso, observarás brechas — usa la comparación de obsolescencia
<= de arriba, nunca detección de brechas.¿Por qué tanto sequence como originalCreateDate?
Responden preguntas diferentes. originalCreateDate te dice cuándo ocurrió un cambio de estado — tiempo de reloj, útil para visualización, registros de auditoría y consultas por ventana de tiempo. Pero el tiempo de reloj es una clave de ordenamiento poco confiable: dos transiciones rápidas en el mismo recurso pueden caer tan cerca una de otra que sus marcas de tiempo colisionan, y una comparación de marcas de tiempo no tiene forma de romper el empate. sequence existe para hacer que el ordenamiento sea inequívoco — un entero estrictamente creciente por instancia de recurso, de modo que dos eventos cualesquiera del mismo recurso siempre tienen un orden definido, sin importar qué tan cerca ocurrieron.
Regla general: ordena y deduplica por sequence; visualiza y audita por originalCreateDate.
El campo applicationId
Cada payload incluye data.applicationId — la aplicación de SpherePay a la que pertenece el evento. Los endpoints de webhook se registran por aplicación, y los eventos solo se entregan para recursos que pertenecen a la aplicación del endpoint.
Esto importa sobre todo cuando operas múltiples aplicaciones de SpherePay que comparten una misma URL receptora de webhooks. Registrar la misma URL bajo dos aplicaciones es perfectamente válido — pero tu handler entonces recibe eventos de ambas, y el endpoint de cada aplicación tiene su propio secreto de firma. Usa applicationId para enrutar cada evento al contexto de aplicación correcto en tu sistema (y para seleccionar el secreto correcto al verificar firmas).