08 — Política de reintentos

Calendario de reintentos

Un evento fallido se reintenta hasta 8 intentos en total, con espera creciente entre cada uno:

IntentoEspera desde el intento anteriorTiempo acumulado desde el fallo original
1— (inmediato)0 s
21 s1 s
35 s6 s
430 s36 s
5~4 min 24 s5 min
630 min35 min
7~1 h 55 min2 h 30 min
8~9 h 30 min12 h

Si el intento 8 también falla, la entrega pasa a ABANDONED y no se reintenta más automáticamente — a partir de ahí, solo un reintento manual la reactiva (ver abajo).

Qué se reenvía

Cada intento, automático o manual, reenvía el mismo evento: mismo id, created_at y data, tal como quedaron al ocurrir. No se vuelve a armar con el estado actual del cobro; si necesitas el estado de ahora, consulta GET /v1/transactions/{id}. También se repiten X-Yallego-Event-Id y X-Yallego-Delivery-Id. Solo cambian X-Yallego-Timestamp y la firma, que se calcula en cada intento sobre el cuerpo enviado.

Entre un intento y el siguiente la entrega queda en PENDING, con next_attempt_at y el resultado del intento anterior en last_status_code y last_error (ver historial de entregas).

Las entregas creadas antes de que el sobre incluyera tenant_id y livemode se reenvían con esos dos campos agregados; el resto del evento no cambia.

Qué cuenta como fallo

  • Cualquier código de respuesta fuera del rango 2xx.
  • Timeout: tu endpoint tiene 10 segundos para responder antes de que Yallegó considere el intento fallido.
  • Error de red (conexión rechazada, TLS, corte).
  • Una redirección (3xx): las entregas no siguen redirecciones — si tu endpoint responde con un 301/302, cuenta como fallo. Configura la URL registrada para que apunte directo al destino final.
  • El dominio no resuelve: antes de cada intento Yallegó resuelve el dominio de tu URL. Si la consulta falla (el dominio no existe, el DNS no responde o tarda más de 5 segundos), el intento cuenta como fallido sin enviarse: last_status_code queda en null y last_error dice «No se pudo resolver el dominio del webhook (CÓDIGO).», por ejemplo con ENOTFOUND o EAI_AGAIN. Un corte de DNS de tu lado retrasa las entregas, no las pierde.

Todos esos fallos siguen el calendario. Dos casos no lo siguen y abandonan la entrega en el acto, sin más reintentos:

  • 410 Gone (abajo).
  • El dominio resuelve a una red interna: si alguna de las direcciones de tu dominio es privada, de loopback o de otro rango reservado, la entrega pasa a ABANDONED sin enviarse y cuenta como un fallo consecutivo del endpoint. Es una protección de seguridad (SSRF), no un error pasajero.

La excepción: 410 Gone

Si tu endpoint responde explícitamente 410 Gone, Yallegó lo interpreta como "este endpoint ya no existe, deja de intentar" — la entrega se marca ABANDONED de inmediato (sin agotar los 8 intentos) y el endpoint se deshabilita en el acto, sin esperar el umbral de fallos consecutivos descrito abajo. Úsalo si estás retirando una integración permanentemente en vez de dejar que expire por fallos.

Desactivación automática por fallos sostenidos

Si un endpoint acumula 5 entregas ABANDONED consecutivas (cada una ya agotó sus 8 intentos, recibió un 410 o su dominio resolvió a una red interna), Yallegó lo deshabilita automáticamente (is_enabled: false) y notifica por correo a los usuarios con rol OWNER o ADMIN del negocio. Un endpoint deshabilitado deja de recibir nuevos eventos hasta que lo reactives explícitamente con PATCH /v1/webhooks/{id} ({"is_enabled": true}).

Este umbral es una decisión operativa propia de Yallegó (no forma parte de un estándar externo) — su intención es detectar un endpoint roto en horas, no dejarlo fallando silenciosamente durante semanas mientras acumula entregas perdidas.

Cualquier entrega exitosa reinicia el contador de fallos consecutivos (consecutive_failures) a cero. Las entregas que se abandonan porque el endpoint ya estaba deshabilitado no suman.

Reintento manual

Para reactivar una entrega puntual sin esperar el calendario automático — por ejemplo, después de corregir un bug que causó el fallo original:

curl -X POST https://api.yallego.app/v1/webhooks/{id}/deliveries/{deliveryId}/retry \
  -H "Authorization: Bearer yk_live_..."

Aplica a entregas ABANDONED y también a las PENDING (adelanta su próximo intento); una DELIVERED responde 409 CONFLICT. El reintento manual no crea una entrega nueva: reactiva la misma (mismo id, mismo X-Yallego-Delivery-Id, mismo cuerpo) y hace un intento inmediato. En una PENDING, ese intento es el que estaba agendado, adelantado: cuando llega la hora original no se envía otro.

  • attempts sigue contando desde donde estaba, así que puede superar max_attempts.
  • Si a la entrega le quedaban intentos del calendario (por ejemplo, se abandonó en el primero porque el endpoint estaba deshabilitado o su dominio resolvía a una red interna), un fallo sigue el calendario desde ahí.
  • Si ya había agotado los 8, ese intento es el único: si falla, vuelve a ABANDONED y suma un fallo consecutivo al endpoint, como cualquier otra entrega abandonada.
  • Si el endpoint está deshabilitado, la entrega se abandona sin enviarse: reactívalo antes con PATCH /v1/webhooks/{id} ({"is_enabled": true}).

Recomendaciones para tu endpoint

  • Responde 2xx en cuanto valides la firma y encoles el procesamiento — no hagas trabajo pesado de forma síncrona dentro del handler, o corres riesgo de superar los 10 segundos de timeout.
  • Diseña tu handler para ser idempotente: un mismo evento puede llegarte más de una vez si tu respuesta se perdió en tránsito aunque tu handler sí lo haya procesado. Para descartar duplicados:
    • X-Yallego-Event-Id (= id del cuerpo) es único por evento y se repite en todos los intentos. Guarda los que ya procesaste y descarta los repetidos.
    • X-Yallego-Delivery-Id también se repite en todos los intentos de una entrega, automáticos y manuales: no es único por intento. Identifica la entrega de ese evento a ese endpoint y es el id que ves en GET /v1/webhooks/{id}/deliveries, así que sirve para cruzar tus registros con el historial.
    • Si el mismo comercio tiene varios endpoints suscritos al mismo tipo, el evento llega una vez a cada uno, con el mismo X-Yallego-Event-Id y un X-Yallego-Delivery-Id distinto: deduplica por X-Yallego-Event-Id si quieres procesarlo una sola vez, o por X-Yallego-Delivery-Id si cada endpoint lo procesa por su cuenta.
    • El evento de prueba (POST /v1/webhooks/{id}/test) tiene un id nuevo en cada llamada.
  • Monitorea GET /v1/webhooks/{id}/deliveries?status=ABANDONED periódicamente, o suscribe activamente a que tu propio sistema te alerte — no dependas solo del correo de desactivación automática como única señal.