Retries and delivery
How Certivant retries failed webhook deliveries — exact backoff schedule, 10-second timeout rule, exhausted-event recovery, and a fast handler pattern to stay under budget.
Certivant is designed to deliver every event at least once. If your endpoint is briefly unavailable — a deploy, a database hiccup, a 30-second outage — retries make sure the event still gets through. This page explains the exact behaviour so you can plan accordingly.
The retry policy at a glance
| Value | |
|---|---|
| Max delivery attempts | 5 (including the first try) |
| Retry schedule | 5s, 30s, 5min, 1h, 24h, each with ±10% jitter |
Retry-After | Honoured on any failed attempt (seconds or an HTTP date, capped at 24 h): the next attempt is never earlier than you asked |
| Per-attempt timeout | 10 seconds |
| Success criterion | HTTP status 200–299 |
| Failure criteria | Status >= 300, timeout, connection error, DNS failure |
| Total delivery window | ~25 hours from first attempt |
After the fifth failed attempt, the event is marked exhausted. It will not be retried automatically. An email is sent to the organization owner alerting them that webhooks are failing.
The timeline
gantt
title Webhook delivery attempts
dateFormat X
axisFormat %s
section Attempts
Attempt 1 (immediate) :a1, 0, 1s
Attempt 2 (+5s) :a2, 5, 1s
Attempt 3 (+30s) :a3, 35, 1s
Attempt 4 (+5min) :a4, 335, 1s
Attempt 5 (+1h) :a5, 3935, 1s
Attempt 6 (+24h) :a6, 90335, 1s
The clock starts when the event is generated. If your endpoint is healthy on attempt 1, you never see retries. If it's down for the full ~25 hours, the event exhausts.
A short transient outage (a deploy, a database failover, anything under a minute) is fully absorbed by the schedule — your endpoint will see the next attempt about 5 seconds later and succeed.
What counts as success
Certivant treats your endpoint as healthy when:
- The HTTP status is
2xx(200,201,204, etc.). - The response arrives within 10 seconds of the request being sent.
Anything else is a delivery failure:
3xxredirects — Certivant does not follow redirects. Point the webhook URL at the final destination.4xx(including401and404) — Certivant retries anyway, in case the problem is transient (cold-start auth check, route-not-yet-deployed). Most integrations want to investigate any 4xx — it usually indicates a misconfiguration on your side.5xx— server error. Standard retry.- Connection refused, DNS failure, TLS handshake error — same retry behaviour.
- No response within 10 seconds — Certivant aborts the request and counts it as a failure. Retry continues.
Designing a fast handler
You have a 10-second budget. Do the bare minimum synchronously:
app.post("/webhooks/certivant", async (c) => {
const rawBody = await c.req.text();
// 1. Verify signature
if (!verifyCertivantSignature(rawBody, c.req.header("X-Certivant-Signature-V2"), SECRET)) {
return c.json({ error: "Invalid signature" }, 401);
}
// 2. Persist to queue (single DB write, fast)
const eventId = c.req.header("X-Certivant-Event-Id")!;
await db.webhookEventQueue.create({
data: { id: eventId, payload: rawBody },
});
// 3. Acknowledge immediately
return c.json({ received: true }, 200);
});
// Process the queue asynchronously
async function workerLoop() {
while (true) {
const event = await db.webhookEventQueue.findFirst({ where: { processedAt: null } });
if (!event) { await sleep(1000); continue; }
try {
await handleEvent(JSON.parse(event.payload));
await db.webhookEventQueue.update({ where: { id: event.id }, data: { processedAt: new Date() } });
} catch (err) {
// Bounded retry on your side; surface after N attempts
}
}
}
This pattern decouples acknowledgement (must be fast) from business logic (can be slow / retried independently). Your downstream services (sending welcome emails, provisioning accounts, etc.) can fail without making Certivant retry.
When your endpoint is genuinely down
If you're going to be down for an extended window (maintenance, migration), the retries will still cover you for ~25 hours. Beyond that:
- Events that exhaust are still queryable via
GET /api/v1/kyc/requests/:id— the current state is always available on the request itself. Walk the requests created during your downtime and sync state manually. - The organization owner gets an email when an event exhausts. The email includes the request ID so it's easy to look up.
- Webhook delivery status (delivered / failed / exhausted), the attempt count, the last response code and the next scheduled retry are visible in the dashboard at KYC → Settings → Webhooks → Delivery log, where each failed or exhausted event has a Retry now button (and a bulk retry).
Re-delivering an exhausted event
From the delivery log, Retry now re-sends a failed or exhausted event immediately, signed with the current secret, and restarts its attempt counter. There is no public (API-key) endpoint to re-trigger a single event. Other options:
- Pull state via the API.
GET /api/v1/kyc/requests/:idalways returns the current state including the final decision. This is the right answer for catch-up after downtime. - Ask support to replay if you're missing a large batch. Include the request IDs or the time window — support can re-emit events for you.
Rate limit interaction
Webhook delivery does not count against your API key rate limit — those are separate systems. You can be receiving hundreds of webhooks per minute while also making hundreds of API calls per minute on the same key, and neither budget affects the other.
Idempotency revisited
Because retries exist, the same logical event will sometimes arrive twice. See Events → Idempotency for the recommended deduplication pattern using X-KYC-Event-Id.
Monitoring suggestions
A healthy webhook integration has:
- Median response time on the webhook endpoint under 500ms. If it climbs, you risk hitting the 10-second timeout under load.
- Zero
4xxand5xxfrom the webhook URL in normal operation. Alert on either. - An idempotency log table you can query to confirm every webhook was processed at least once.
If you're seeing exhausted-event emails, the most common root causes are: (a) the webhook URL is wrong (typo in the dashboard), (b) your endpoint requires auth that Certivant doesn't provide (the URL must accept unauthenticated POSTs — the signature header is the auth), (c) your endpoint is consistently slower than 10 seconds. Investigate each.
Webhook events
Complete reference for every Certivant webhook event type — envelope schema, per-event payload shapes, idempotency pattern, and ordering rules.
Automation Workflows
Event-triggered, executable workflows that route, notify, and orchestrate around a verification — without ever setting the verdict.