Reintentos, orden y versionado

Cómo entregamos, qué garantizamos y cómo escribir un consumidor a prueba de fallas.

Reintentos

Si tu endpoint no responde 2xx en 10 segundos, reintentamos con espera exponencial durante 24 horas: 30 segundos, 2 minutos, 10 minutos, 1 hora, 6 horas y 24 horas.

Después de 20 entregas fallidas seguidas, o 5 días de fallas continuas, pausamos el webhook y te avisamos por email y con el evento webhook.disabled. Reactivarlo desde Configuración, Desarrolladores no pierde el historial.

Códigos de respuesta

CampoTipoDescripción
2xxéxitoLa entrega se marca como completada.
410baja definitivaDamos de baja el webhook sin reintentar.
429reintentoRespetamos el header Retry-After si viene.
otros 4xx y 5xxreintentoEntra en la cola de reintentos.

Idempotencia

Un mismo evento puede llegar más de una vez: garantizamos entrega al menos una vez, no exactamente una vez.

Guardá el id del evento y descartá los repetidos. Es la forma más simple de volverte inmune a los reintentos.

async function handle(event) {  // Insert que falla si el id ya existe: el evento repetido se descarta solo.  const inserted = await db.processedEvents.insertIfAbsent(event.id);  if (!inserted) return;  await process(event);}

Orden de entrega

No garantizamos el orden. Un conversation.closed puede llegar antes que un message.created de la misma conversación.

Usá occurred_at para ordenar y, si tu lógica depende del estado final, leé el objeto por API antes de escribir.

Nunca reconstruyas el estado sumando eventos en orden de llegada. Reconciliá contra la API cuando el orden importa.

Versionado

Cada entrega incluye api_version. La actual es 2026-09-01.

Agregar un evento nuevo o un campo nuevo dentro de data no se considera un cambio que rompa. Tu consumidor debe ignorar lo que no conoce.

Los cambios que rompen se publican como una versión nueva, con seis meses de convivencia y aviso previo.

Direcciones de salida

Si tu firewall filtra por IP, permití estas direcciones. Avisamos con 30 días de anticipación antes de cambiarlas.

Texto
52.14.108.0/2435.171.44.0/2418.229.201.0/24

Historial de entregas

Guardamos cada intento durante 30 días, con el cuerpo enviado, la respuesta de tu servidor, el código, la duración y el número de intento. Está en Configuración, Desarrolladores, Webhooks, y también por API.

Sirve para dos cosas: entender por qué falló algo sin pedirnos logs, y recuperar eventos que tu sistema perdió durante una caída sin tener que reprocesar toda la base.

GET/v1/webhooks/{id}webhooks:read

Devuelve el endpoint con su tasa de éxito, latencia p95 y fallos consecutivos.

GET/v1/webhooks/{id}/deliverieswebhooks:read

Lista los intentos de entrega, del más nuevo al más viejo.

CampoTipoDescripción
statusstringsuccess, failed o pending.
eventstringFiltra por nombre de evento.
limitnumberMáximo 100.
PATCH/v1/webhooks/{id}webhooks:write

Cambia la URL, los eventos o pausa el endpoint.

DELETE/v1/webhooks/{id}webhooks:write

Da de baja el endpoint y su historial.

curl "https://api.tinkay.app/v1/webhooks/wh_1/deliveries?status=failed&limit=50"   -H "Authorization: Bearer dk_live_xxx"

Buenas prácticas

  • Respondé 200 antes de procesar. Encolá y trabajá asincrónicamente.
  • Verificá la firma en todas las entregas, también en producción.
  • Guardá el cuerpo crudo unos días: sirve para reprocesar sin pedir reenvíos.
  • Monitoreá el registro de entregas en Configuración, Desarrolladores: ahí ves código, duración e intento de cada una.
  • Usá Reenviar para reprocesar una entrega puntual después de arreglar un bug.