Guides by flow
Forecast, watch and webhooks
Subscribe, receive the alert, verify the HMAC signature, handle retries and the DLQ.
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
Verifying the signature
Every delivery carries these headers:
| Header | What it is |
|---|---|
x-ucotron-event-id | The event id |
x-ucotron-signature-timestamp | When it was signed |
x-ucotron-payload-digest | SHA-256 of the canonical payload |
x-ucotron-signature | HMAC-SHA256 of eventId.timestamp.digest |
Verify in this order: id, time window (300 s), duplicate, digest,
signature. Comparing the signature with === instead of constant time turns
your receiver into an oracle.
Retries and the DLQ
Three attempts at most, with deterministic backoff (1 s, 5 s, 15 s). Only 408, 429, 500, 502, 503 and 504 are retried: a 400 is not fixed by retrying.
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"The sandbox seeds one delivery in each final state — delivered,
retry_scheduled and dlq — on purpose. If you could only exercise the 200,
you would write your retry handling by looking at this page.
What breaks
- Only what landed in the DLQ can be retried. Retrying something already
delivered would duplicate the event on the receiver's side:
409 delivery_not_replayable. - An endpoint pointing at a private IP or the cloud metadata service is
rejected with
ssrf_blockedbefore any attempt. - The same event delivered twice is detected as
replay_detected. Your receiver must be idempotent anyway: the network does not promise exactly-once delivery.