Ucotron Cortex
Guías por flujo

Forecast, watch y webhooks

Suscribirse, recibir la alerta, verificar la firma HMAC, manejar retries y DLQ.

Diagrama: Forecast, watch y webhooksFlujo del ciclo de webhooks: la suscripción de watch produce entregas con firma, con reintentos, DLQ y replay manual.

2xx

5xx

falla

POST /v1/watch/subscriptions

Alerta

Evento de webhook

Intento 1

delivered

retry_scheduled

Intento 3

dlq

POST .../replay

Diagrama: Forecast, watch y webhooksFlujo del ciclo de webhooks: la suscripción de watch produce entregas con firma, con reintentos, DLQ y replay manual.

2xx

5xx

falla

POST /v1/watch/subscriptions

Alerta

Evento de webhook

Intento 1

delivered

retry_scheduled

Intento 3

dlq

POST .../replay

Fuente del diagrama (mermaid)
flowchart LR
    W[POST /v1/watch/subscriptions] --> A[Alerta]
    A --> E[Evento de webhook]
    E --> D1[Intento 1]
    D1 -- 2xx --> OK[delivered]
    D1 -- 5xx --> D2[retry_scheduled]
    D2 --> D3[Intento 3]
    D3 -- falla --> DLQ[dlq]
    DLQ --> RP[POST .../replay]
    RP --> OK

Verificar la firma

Cada entrega trae estos headers:

HeaderQué es
x-ucotron-event-idEl id del evento
x-ucotron-signature-timestampCuándo se firmó
x-ucotron-payload-digestSHA-256 del payload canónico
x-ucotron-signatureHMAC-SHA256 de eventId.timestamp.digest

Verificá en este orden: id, ventana de tiempo (300 s), duplicado, digest, firma. Comparar la firma con === en vez de en tiempo constante convierte tu receptor en un oráculo.

Retries y DLQ

Tres intentos como máximo, con backoff determinista (1 s, 5 s, 15 s). Sólo se reintentan 408, 429, 500, 502, 503 y 504: un 400 no se arregla reintentando.

Ciclo de vida de una entrega de webhook Un evento de la suscripción de watch produce una entrega firmada. Si el endpoint responde 2xx queda entregada. Si falla con un status reintentable, se reintenta con backoff determinista (1, 5 y 15 segundos, tres intentos como máximo); agotados los reintentos cae a la cola de mensajes muertos (DLQ), desde donde un replay manual vuelve a generar una entrega. Cada intento queda auditado con su firma y su respuesta. EVENTO del watch forecast.watch.triggered DELIVERY POST firmado (HMAC) a tu endpoint 2xx ENTREGADO 408 · 429 · 5xx reintentable RETRY 1 s · 5 s · 15 s — máximo tres intentos reintenta reintentos agotados DLQ cola de muertos, visible por API REPLAY manual POST …/deliveries/:id/replay nueva entrega Cada intento queda auditado: número, timestamp, firma enviada y respuesta recibida. El replay no reescribe la historia — genera una entrega nueva.
bash
curl -sS "$SBOX/v1/webhooks/deliveries?limit=250" -H "authorization: Bearer $TOKEN"
curl -sS "$SBOX/v1/webhooks/deliveries/<deliveryId>/replay" -X POST \
  -H "authorization: Bearer $TOKEN" -H "idempotency-key: replay-demo-1"

El sandbox siembra una entrega en cada estado finaldelivered, retry_scheduled y dlq— a propósito. Si sólo pudieras ejercitar el 200, escribirías el manejo de reintentos mirando esta página.

Lo que se rompe

  • Sólo se reintenta lo que quedó en DLQ. Reintentar algo ya entregado duplicaría el evento del lado del receptor: 409 delivery_not_replayable.
  • Un endpoint que apunta a una IP privada o al metadata del cloud se rechaza con ssrf_blocked antes de cualquier intento.
  • El mismo evento entregado dos veces se detecta como replay_detected. Tu receptor tiene que ser idempotente igual: la red no promete entrega única.

Endpoints de esta guía

On this page