Leypal API Docs

Errores y Solución de Problemas de Webhook

Referencia completa de códigos de respuesta HTTP, comportamiento de reintentos, errores de verificación de firma y un diagrama de flujo de diagnóstico paso a paso.

Errores y Solución de Problemas de Webhook

La entrega de webhooks es asíncrona. Tu punto final debe ser accesible públicamente, responder dentro de la ventana de tiempo límite y devolver los códigos de estado HTTP correctos. Cuando algo sale mal — errores de red, discrepancias de firma o fallos del punto final — Leypal reintenta la entrega automáticamente usando retroceso exponencial.

Esta guía cubre tres categorías de problemas que puedes encontrar:

  1. Códigos de respuesta HTTP — qué significa cada código y cómo reacciona Leypal
  2. Errores de verificación de firma — causas comunes y soluciones para fallos de autenticación
  3. Problemas de entrega — accesibilidad, tiempos de espera y fallos permanentes

Usa el diagrama de flujo de solución de problemas para diagnosticar fallos desconocidos, y la lista de verificación de producción antes de poner en marcha.


Qué Envía Leypal

Cada webhook es una solicitud HTTPS POST con las siguientes propiedades:

PropiedadValor
MétodoPOST
Content-Typeapplication/json
X-Leypal-SignatureFirma HMAC-SHA256 del cuerpo de la solicitud sin procesar
CuerpoPayload JSON (consulta Eventos de Webhook para la estructura completa)
Tiempo límite30 segundos — Leypal cierra la conexión después de 30 segundos sin respuesta

Importante: Leypal firma los bytes del cuerpo de la solicitud sin procesar, no una cadena JSON serializada. Tu punto final debe leer el cuerpo sin procesar antes de analizarlo para verificar la firma correctamente.

Para los detalles de implementación de la verificación de firma, consulta Verificación de Firma de Webhook.


Códigos de Respuesta HTTP

Leypal trata cualquier respuesta 2xx como una entrega exitosa. Cualquier respuesta que no sea 2xx (incluyendo redirecciones y tiempos de espera) activa la política de reintentos.

2xx — Éxito (Sin Reintento)

CódigoEstadoComportamientoTu Acción
200OKWebhook entregado con éxitoRespuesta predeterminada — devuelve esto cuando recibes y confirmas el webhook
201CreatedWebhook procesado; recurso creadoAceptable si tu manejador crea un recurso como parte del procesamiento
202AcceptedWebhook en cola para procesamiento en segundo planoRespuesta ideal — señala que recibiste el payload y lo procesarás de forma asíncrona
204No ContentWebhook recibido; sin cuerpo de respuestaAceptable si prefieres no enviar un cuerpo de respuesta

Mejor práctica: Devuelve 200 o 202 inmediatamente, antes de ejecutar cualquier lógica de negocio. Procesar el webhook en el manejador de solicitudes (p. ej., consultar la base de datos, enviar correos) añade latencia y arriesga superar el tiempo límite de 30 segundos. En su lugar, encola el evento y procésalo en un trabajo en segundo plano.

3xx — Redirecciones (Fallo + Reintento)

CódigoEstadoComportamientoTu Acción
301Moved PermanentlyWebhook marcado como fallido; Leypal NO sigue redireccionesActualiza la URL del webhook en el panel de control al destino final
302FoundIgual que 301Actualiza la URL del webhook para evitar la redirección
307Temporary RedirectIgual que 301Verifica que la URL del punto final sea la URL canónica

Las redirecciones indican una mala configuración. Leypal reintentará hasta 5 veces, pero cada intento llega a la misma redirección. Actualiza la URL del webhook en tu panel de control de Claves API para apuntar directamente al punto final final.

4xx — Errores del Cliente (Fallo + Reintento)

CódigoEstadoComportamientoTu Acción
400Bad RequestEl punto final rechazó el formato de la solicitudVerifica tu lógica de verificación de firma; verifica el orden del middleware
401UnauthorizedVerificación de firma fallida o encabezado faltanteConsulta Errores de Verificación de Firma
403ForbiddenEl punto final existe pero rechazó la solicitudVerifica tu lógica de autorización; confirma que la solicitud es de Leypal
404Not FoundLa ruta del webhook no existeVerifica la URL del punto final en el panel de control; revisa el enrutamiento del servidor
408Request TimeoutEl punto final tardó más de 30 segundos en responderDevuelve 202 inmediatamente; mueve el procesamiento a un trabajo en segundo plano
429Too Many RequestsLímite de velocidad superado en tu punto finalImplementa una exención de límite de velocidad para el rango de IPs de Leypal, o eleva tus límites

Todas las respuestas 4xx se reintentan hasta 5 veces. Leypal asume que el error puede ser transitorio (p. ej., una sobrecarga breve o una condición de carrera). Corrige la causa raíz — los reintentos eventualmente tendrán éxito o agotarán los intentos.

401 y 403 son los códigos más comunes durante la configuración inicial. Si los ves, ve directamente a Errores de Verificación de Firma.

5xx — Errores del Servidor (Fallo + Reintento)

CódigoEstadoComportamientoTu Acción
500Internal Server ErrorEl punto final lanzó una excepción no manejadaRevisa los registros del servidor; corrige el error y vuelve a desplegar
502Bad GatewayEl proxy inverso no pudo llegar a tu aplicaciónVerifica que el servidor de la aplicación esté funcionando; revisa la configuración de nginx/caddy/ALB
503Service UnavailablePunto final sobrecargado o en modo de mantenimientoEscala hacia arriba o reduce el tiempo de procesamiento por solicitud
504Gateway TimeoutEl proxy desistió de esperar a tu aplicaciónDevuelve 202 inmediatamente; reduce el tiempo de ejecución del manejador

Todas las respuestas 5xx se reintentan hasta 5 veces. Estas son temporales por definición — la suposición es que tu servidor se recuperará. Revisa los registros de tu aplicación para ver los stack traces.

Errores de Red (Fallo + Reintento)

Tipo de ErrorComportamientoTu Acción
Conexión rechazadaReintentado hasta 5 vecesVerifica que el punto final esté ejecutándose y escuchando en el puerto correcto
Fallo de resolución DNSReintentado hasta 5 vecesVerifica que el DNS del dominio esté configurado; verifica con dig tupuntofinalf.com
Tiempo de espera de conexiónReintentado hasta 5 vecesVerifica que el firewall permita HTTPS entrante (puerto 443)
Error TLS/SSLReintentado hasta 5 vecesAsegúrate de que el certificado SSL sea válido; verifica la cadena de certificados

Nota de desarrollo local: Leypal no puede llegar a localhost o 127.0.0.1. Usa ngrok o localtunnel para crear un túnel público a tu servidor local.


Política de Reintentos

Cuando falla una entrega de webhook, Leypal reintenta automáticamente con retroceso exponencial:

IntentoRetrocesoTiempo Acumulado Después del Primer Fallo
1Entrega inicial (sin retroceso)0 min
2~5 minutos~5 min
3~10 minutos~15 min
4~20 minutos~35 min
5~40 minutos~75 min

Después del 5° intento fallido, el webhook se marca como permanentemente fallido. No se realizan más reintentos. Para recibir el evento de nuevo, debes activar la acción que lo causó (p. ej., crear una nueva solicitud de firma).

Un webhook se marca como exitoso cuando:

  • Leypal recibe una respuesta 2xx de tu punto final antes del tiempo límite de 30 segundos

Un webhook se marca como fallido cuando:

  • Los 5 intentos se agotan sin una respuesta 2xx
  • Cada intento resulta en un error de red (punto final inaccesible)

Nota de idempotencia: Dado que Leypal reintenta en caso de fallo, tu punto final puede recibir el mismo evento más de una vez. Siempre implementa procesamiento idempotente — usa el campo webhookId para detectar y omitir entregas duplicadas.


Errores de Verificación de Firma

Estos errores ocurren cuando tu punto final devuelve 401 Unauthorized o cuando tu verificación de firma falla silenciosamente.

ErrorCausaSíntomaSolución
Firma inválidaEl HMAC calculado no coincide con el encabezado X-Leypal-SignatureEl punto final devuelve 401; los registros muestran discrepancia de firmaConsulta las soluciones a continuación
Encabezado X-Leypal-Signature faltanteWebhook no registrado o secreto no generadoEncabezado ausente en req.headersVerifica la URL del webhook y el secreto en el panel de control de Claves API
Punto final no accesibleLeypal no puede conectarse a tu URLEl webhook aparece como fallido en el historial; responseCode es nullRevisa firewall, DNS, disponibilidad del punto final
Algoritmo inválidoUsando SHA1, MD5 u otro algoritmo en lugar de SHA256Discrepancia en el formato de la cadena hexadecimal de firmaSiempre usa sha256 con crypto.createHmac de Node.js

Solucionar "Firma Inválida" (401)

La causa más común es una discrepancia entre cómo calculas el HMAC y cómo lo calcula Leypal. Verifica estos puntos en orden:

1. Secreto de webhook incorrecto u obsoleto

El secreto en tu .env debe coincidir exactamente con el que aparece en tu panel de control de Claves API de Leypal. Incluso un espacio extra o un carácter de más hará que cada webhook falle.

# Imprime tu secreto actual (sin salto de línea al final)
echo -n "$WEBHOOK_SECRET" | wc -c
# Compara con el recuento de caracteres mostrado en tu panel de control

Si rotaste recientemente el secreto en el panel de control, actualiza tu .env y vuelve a desplegar inmediatamente.

2. No leer el cuerpo sin procesar

El HMAC se calcula sobre los bytes de la solicitud sin procesar — antes del análisis JSON. Si dejas que Express analice el cuerpo primero, los bytes sin procesar se pierden y no puedes recalcular la firma correcta.

// INCORRECTO — cuerpo JSON analizado; bytes sin procesar perdidos
app.use(express.json());
app.post('/webhooks', (req, res) => {
  // req.body ya es un objeto; no se pueden recuperar los bytes sin procesar
  const sig = computeHmac(webhookSecret, JSON.stringify(req.body)); // FALLA
});

// CORRECTO — cuerpo sin procesar preservado para la ruta de webhook
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  // req.body es un Buffer que contiene los bytes sin procesar
  const sig = crypto.createHmac('sha256', webhookSecret)
    .update(req.body) // Buffer, no cadena
    .digest('hex');
  // ahora compara con el encabezado X-Leypal-Signature
});

3. Usar igualdad de cadenas en lugar de comparación segura en tiempo

// INCORRECTO — ataque de temporización posible
if (computedSig === req.headers['x-leypal-signature']) { ... }

// CORRECTO — seguro en tiempo
const a = Buffer.from(computedSig);
const b = Buffer.from(req.headers['x-leypal-signature']);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
  return res.status(401).send('Invalid signature');
}

Para una implementación completa, consulta Verificación de Firma de Webhook.

Solucionar "Encabezado X-Leypal-Signature Faltante"

Si el encabezado está ausente en cada solicitud, es posible que el webhook no esté registrado:

  1. Ve a tu panel de control de Claves API → sección Webhooks
  2. Verifica que la URL de tu punto final esté listada y Activa
  3. Verifica que se haya generado un secreto de webhook (haz clic en el campo del secreto — debería mostrar sk_webhook_xxx)
  4. Si el secreto fue eliminado o nunca se creó, haz clic en Generar Secreto y copia el nuevo valor a tu .env

API de Historial de Entrega de Webhook

Cuando un webhook no llega, el historial de entregas es el primer lugar donde buscar. Muestra exactamente qué envió Leypal, qué devolvió tu punto final y por qué falló la entrega.

Punto final: GET /api/v1/webhook-notifications

Autenticación: Clave API como token Bearer

curl -X GET https://api.leypal.dev/api/v1/webhook-notifications \
  -H "Authorization: Bearer sk_live_xxx" \
  -H "Content-Type: application/json"

Parámetros de consulta opcionales:

ParámetroTipoDescripción
eventstringFiltrar por tipo de evento (p. ej., signature.created)
statusstringFiltrar por estado de entrega: success, failed, pending
limitnumberResultados por página (predeterminado: 50, máx: 100)
offsetnumberDesplazamiento de paginación

Campos de respuesta por registro de entrega:

CampoTipoDescripción
idstringID del registro de notificación
eventstringTipo de evento (p. ej., signature.completed)
webhookIdstringID único de entrega del webhook (coincide con el encabezado X-Leypal-Webhook-Id)
organizationIdstringTu ID de organización
statusstringsuccess | failed | pending
requestBodyobjectPayload JSON exacto que Leypal envió
responseCodenumberCódigo de estado HTTP que devolvió tu punto final
responseBodystringCuerpo de respuesta que envió tu punto final
responseHeadersobjectEncabezados de respuesta que envió tu punto final
deliveredAtstringMarca de tiempo ISO 8601 del intento de entrega
nextRetryAtstringMarca de tiempo ISO 8601 del próximo reintento (si está pendiente/fallido)
failureReasonstringPor qué falló el webhook (p. ej., "connection timeout")
attemptsnumberTotal de intentos de entrega realizados hasta ahora

Cuándo usar esto: Si un webhook nunca llega, consulta este punto final para ver si Leypal intentó la entrega. Si no existe ningún registro, el evento desencadenante no se activó. Si existe un registro, responseCode y failureReason te dicen exactamente qué salió mal.


Diagrama de Flujo de Solución de Problemas

Usa este diagrama de flujo para diagnosticar problemas de entrega de webhook de forma sistemática:

Mi webhook no se está entregando

├─ Paso 1: ¿Está la URL del webhook registrada en tu panel de control de Claves API?
│  ├─ No → Ve al panel de control de Claves API → Webhooks → Añadir URL → Generar Secreto
│  └─ Sí → Continúa al Paso 2

├─ Paso 2: ¿Es tu punto final accesible públicamente desde internet?
│  ├─ No (localhost/privado) → Usa ngrok o localtunnel para pruebas
│  │                           Despliega en un servidor público para producción
│  └─ Sí → Continúa al Paso 3

├─ Paso 3: ¿Intentó Leypal la entrega?
│  │  Verifica: GET /api/v1/webhook-notifications?status=failed
│  ├─ No se encontraron registros → El evento desencadenante no se activó
│  │                                Verifica que realizaste la acción (p. ej., creaste una firma)
│  └─ Registros encontrados → Continúa al Paso 4

├─ Paso 4: ¿Qué muestra el registro de entrega?
│  ├─ responseCode: 2xx → El webhook fue entregado; revisa los registros de tu propia aplicación
│  ├─ responseCode: 401 → Verificación de firma fallando
│  │                       Consulta: sección Errores de Verificación de Firma
│  ├─ responseCode: 4xx → El punto final rechazó la solicitud
│  │                       Consulta: sección Códigos de Respuesta HTTP
│  ├─ responseCode: 5xx → El punto final falló o devolvió un error
│  │                       Verifica: Registros de tu servidor para stack traces
│  └─ responseCode: null → Error de red; Leypal no pudo conectarse
│                           Continúa al Paso 5

├─ Paso 5: ¿Puede Leypal llegar a tu punto final?
│  │  Prueba: curl -X POST https://tupuntofinalf.com/webhooks -d '{}' -v
│  ├─ curl falla → Corrige: reglas de firewall, DNS, certificado SSL, ¿servidor ejecutándose?
│  └─ curl tiene éxito → El manejador del webhook falla al inicio o al principio de la solicitud
│                         Verifica: Registros de la aplicación para errores antes de que se envíe la respuesta

├─ Paso 6: ¿Es la verificación de firma el problema?
│  │  Verifica: ¿Es responseCode 401 en el historial?
│  ├─ Sí → Consulta: sección Errores de Verificación de Firma arriba
│  └─ No → Revisa los registros de la aplicación para errores dentro del manejador del webhook

└─ ¿Sigues sin poder resolver el problema?
   ├─ Habilita el registro detallado en tu manejador de webhook
   ├─ Revisa el historial de webhooks para ver el requestBody y responseBody exactos
   ├─ Verifica tu punto final con: curl -X POST <url> -H "Content-Type: application/json" -d '{"test":true}'
   └─ Contacta al soporte de Leypal con:
      - Tipo de evento que no se está entregando
      - Tu ID de Organización
      - ID del Webhook (del API de historial)
      - Marca de tiempo de la entrega esperada
      - Registros del servidor que muestran lo que recibió tu punto final

Escenarios Comunes y Soluciones

EscenarioLo Que VesCausa RaízSolución
El punto final devuelve 200 pero el webhook aparece como fallidoHistorial: status: failed, responseCode: 200El punto final tardó más de 30 segundos en responder antes de devolver 200Devuelve 202 en menos de 1 segundo; mueve toda la lógica de negocio a una cola en segundo plano
"Firma inválida" aunque el secreto es correctoCada webhook devuelve 401 UnauthorizedCuerpo sin procesar no preservado; o igualdad de cadenas usadaAñade express.raw() antes del middleware JSON; usa crypto.timingSafeEqual()
El webhook funcionaba ayer, se detuvo hoyNo se entregan webhooks desde un momento específicoEl punto final se cayó, o el secreto del webhook fue rotadoVerifica si el punto final está ejecutándose; compara el secreto en .env vs panel de control
El webhook de prueba tiene éxito pero los webhooks reales fallanPrueba manual: entregada; evento real: fallidoURL de punto final diferente (dev vs prod) o diferencia de firewallVerifica que la URL del webhook de producción esté registrada; revisa el firewall de producción
Obteniendo 404 en la entrega del webhookHistorial: responseCode: 404La ruta del webhook no existe en el servidorVerifica la ruta de URL en el panel de control; revisa la configuración de enrutamiento del servidor
Leypal sigue mostrando reintentos pendientes después de la correcciónHistorial: status: pending incluso después de que el punto final está saludableLos reintentos pendientes están en un horario — se ejecutarán en nextRetryAtEspera el próximo reintento; o activa un nuevo evento para generar un webhook fresco
El webhook fue entregado pero el tipo de evento no fue manejadoLa aplicación ignora silenciosamente el eventoEl bloque switch/if no cubre el tipo de eventoRegistra todos los tipos de eventos entrantes; añade un manejador para el evento faltante
El mismo webhook fue entregado dos vecesEntradas duplicadas en tu base de datosEl reintento tuvo éxito; o la red lo entregó dos vecesImplementa idempotencia: verifica webhookId antes de procesar, omite duplicados

Lista de Verificación de Producción

Antes de desplegar tu manejador de webhook a producción, verifica cada elemento:

  • El punto final usa HTTPS (no HTTP)
  • La URL del webhook de producción está actualizada en el panel de control de Claves API de Leypal (no la URL de dev/staging)
  • El secreto del webhook está almacenado en una variable de entorno o gestor de secretos (no codificado directamente)
  • El archivo .env NO está confirmado en git (añadido a .gitignore)
  • Usando crypto.timingSafeEqual() para la comparación de firmas (no ===)
  • Usando el middleware express.raw({ type: 'application/json' }) antes del análisis JSON
  • El punto final devuelve 200 o 202 en menos de 1 segundo
  • La lógica de negocio se procesa de forma asíncrona (sistema de cola o trabajo en segundo plano)
  • webhookId se registra para cada evento entrante (permite la depuración)
  • El historial de entregas de webhook se monitorea periódicamente (GET /api/v1/webhook-notifications)
  • La entrega duplicada se maneja mediante verificación de idempotencia en webhookId
  • El manejo de errores está en su lugar — las excepciones no manejadas devuelven 500 limpiamente, sin bloquear el proceso

Obtener Ayuda

Si has seguido el diagrama de flujo de solución de problemas y el problema persiste, recopila lo siguiente antes de contactar al soporte:

  • Tipo de evento que no se está entregando (p. ej., signature.completed)
  • ID de Organización (visible en tu panel de control)
  • ID del Webhook del API de historial de entregas (campo webhookId)
  • Marca de tiempo de la entrega esperada
  • Registros del servidor del momento del intento de entrega
  • Entrada del historial de webhook que muestra requestBody, responseCode y failureReason

Guías Relacionadas

GuíaQué Cubre
Configuración de WebhookRegistro de puntos finales, generación de secretos, gestión de la configuración de webhook
Verificación de Firma de WebhookImplementación completa de HMAC-SHA256 con ejemplos de código
Eventos de WebhookEstructura completa del payload para todos los tipos de evento

On this page