Retries and the delivery log
At-least-once delivery over five attempts, the stable delivery id you dedupe on, the two-redirect limit, the resend endpoint, and the delivery log.
At-least-once delivery
A delivery that does not return 2xx — or that times out — is retried with exponential backoff on a dedicated queue, up to five attempts in total, so a slow endpoint of yours never holds up anyone else's. Each attempt writes its own row in the delivery log.
That makes delivery at least once, never exactly once. Your endpoint must tolerate seeing the same event twice.
Dedupe on the delivery id
X-Evoriqa-Delivery — and the identical id field in the body — is minted once when the event is emitted and is byte-identical on every retry. It is the dedupe key.
const id = req.get("X-Evoriqa-Delivery");
// A set/table with a TTL is enough; the id is a UUID.
if (await seen.has(id)) {
return res.status(200).end(); // already handled — acknowledge and stop
}
await seen.add(id, { ttlSeconds: 86_400 });
await handle(JSON.parse(req.body.toString("utf8")));
res.status(200).end();The ts field is stable across retries too, so a duplicate is always correlatable with the original rather than looking like a fresh event.
Duplicates can also arrive without a retry: a resend (below) replays a past delivery with the same id and ts. The dedupe key handles both cases identically — though note a resent body is not guaranteed byte-identical (JSON key order may differ), which is why you dedupe on id, not on a body hash.
Redirects
Deliveries follow up to two redirects, and each hop is re-validated against the same protections that block internal and private addresses. That exists so an endpoint behind an http → https upgrade still receives events instead of silently receiving none while appearing active.
Point the endpoint at its final HTTPS URL anyway — a redirect chain is one more thing to fail.
The delivery log
Settings → Webhooks shows recent delivery attempts across your endpoints, newest first, with the event name, the outcome, and the HTTP status your server returned. The same log is available over the API:
curl "https://app.evoriqa.com/api/v1/webhooks/deliveries?take=50" \
-H "x-api-key: $EVORIQA_API_KEY"It is offset-paginated (?skip/?take, take up to 200) and needs the workspace:read scope. Delivery attempts are retained for up to 90 days — and sooner if your workspace's data-retention window is shorter, since delivery payloads carry lead and conversation fields and age out on that same window.
Three optional filters narrow the log, ANDed with each other:
q— a case-insensitive substring match on the event name or the endpoint URL. It is trimmed, and anything past 200 characters is ignored.fromandto— aYYYY-MM-DDdate window on when the attempt was logged.fromis inclusive from the start of that day andtoinclusive to the end, both in UTC, sofrom=2026-08-01&to=2026-08-31covers all of August. A date that is malformed or impossible (2026-02-31) is rejected with a422 VALIDATION_ERROR.
curl "https://app.evoriqa.com/api/v1/webhooks/deliveries?q=lead.created&from=2026-08-01&to=2026-08-31" \
-H "x-api-key: $EVORIQA_API_KEY"Resending a delivery
Any logged delivery can be replayed:
curl -X POST "https://app.evoriqa.com/api/v1/webhooks/deliveries/$DELIVERY_ID/resend" \
-H "x-api-key: $EVORIQA_API_KEY"The replay carries the same delivery id, timestamp, and stored payload as the original, so your dedupe logic sees it as the same event — drop it if you already processed it, or process it if the original never arrived. That stability is the point: a resend can never create a second lead or a duplicate ticket in a correctly deduping consumer.

Use it to answer the three questions that actually come up:
| Question | What to look for |
|---|---|
| "Did Evoriqa send it?" | A log row for the event. No row means it was never emitted. |
| "Did my server accept it?" | The recorded status code — anything outside 2xx is a failure. |
| "Why is my integration seeing doubles?" | Repeated rows for one delivery id: your endpoint is failing after doing the work. Acknowledge before processing. |
That last one is the most common real bug: work is done, the response is slow or errors, Evoriqa retries, and the work happens again. Respond 2xx first, then process — and dedupe regardless.
Where to go next
Last updated
