Delivery Guarantees
Hook Mesh provides an at-least-once delivery guarantee with a 48-hour delivery window. We ensure your webhooks reach their destination, even through temporary failures.
At-Least-Once Delivery
Every webhook job created in Hook Mesh is guaranteed to be delivered at least once (and possibly more than once due to retries). This means your webhook endpoints must be idempotent.
What "At-Least-Once" Means
- ✓ Guaranteed Delivery
- If a webhook job is created and the endpoint is reachable, it WILL be delivered successfully (within 48 hours).
- ⚠ Possible Duplicates
- The same webhook may be delivered multiple times if retries occur. Your endpoint must handle duplicates gracefully using idempotency keys.
- ℹ Order Not Guaranteed
- Webhooks may arrive out of order. Use timestamps or sequence numbers in your payload to handle ordering.
Idempotency Required
Since webhooks can be delivered more than once, your endpoint must be idempotent. Use the event_id field to detect and ignore duplicates.
48-Hour Delivery Window
Hook Mesh will attempt to deliver each webhook for up to 48 hours using exponential backoff retries. This is the longest delivery window in the industry.
| Time Window | Behavior |
|---|---|
| 0 - 4 hours | Aggressive retries (6 attempts with exponential backoff) |
| 4 - 48 hours | Retry every 6 hours until delivered or 48 hours elapsed |
| After 48 hours | Job marked as discarded (permanent failure) |
T+0s: Initial delivery → Failed (500 error)
T+5s: Retry 1 → Failed
T+25s: Retry 2 → Failed
T+2m: Retry 3 → Failed
T+10m: Retry 4 → Failed
T+50m: Retry 5 → Failed
T+4h: Retry 6 → Failed
T+10h: Retry 7 → Failed
T+16h: Retry 8 → Failed
T+22h: Retry 9 → Failed
T+28h: Retry 10 → Failed
T+34h: Retry 11 → Failed
T+40h: Retry 12 → Failed
T+46h: Retry 13 → Failed
T+48h: Final retry → Failed
↓
Job discarded (exceeded 48-hour window)Industry Leading
Hook Mesh's 48-hour delivery window is 8x longer than Stripe (6h), 48x longer than Svix (1h), and 24x longer than Slack (2h). This ensures maximum delivery success even during extended outages.
How We Ensure Delivery
Hook Mesh uses multiple reliability mechanisms to guarantee webhook delivery.
Persistent Job Queue
All webhook jobs are persisted to a durable database before delivery attempts. Jobs survive service restarts and infrastructure failures.
Exponential Backoff Retries
Failed deliveries are automatically retried with exponential backoff (5s, 25s, 2m, 10m, 50m, 4h, then every 6h).
Circuit Breaker
Consistently failing endpoints are paused to prevent wasted attempts. Jobs are queued and delivered when the endpoint recovers.
Distributed Architecture
Webhook delivery service runs on multiple servers with automatic failover. No single point of failure.
Monitoring & Alerting
Automatic health checks and alerts ensure delivery issues are detected and resolved quickly.
When Deliveries Are Discarded
Webhook jobs are only discarded (marked as failed permanently) in specific scenarios.
| Scenario | Action | Reason |
|---|---|---|
| 48 hours elapsed | Discarded | Exceeded maximum retry window |
| 4xx error (except 429) | Discarded | Client error (won't succeed on retry) |
| Endpoint deleted | Discarded | Destination no longer exists |
| Application deleted | Discarded | Parent resource deleted |
| 5xx error | Retried | Temporary server error |
| Timeout | Retried | Network issue |
| Connection error | Retried | Endpoint temporarily unreachable |
Return Correct Status Codes
Always return 2xx if the webhook was processed successfully, even if there's a business logic error. Use 5xx only for server errors that should trigger retries.
Comparing Delivery Models
Different webhook providers offer different delivery guarantees.
| Guarantee | Description | Provider Example |
|---|---|---|
| At-least-once | Guaranteed delivery, possible duplicates | Hook Mesh, Stripe, Svix |
| Exactly-once | No duplicates, but requires distributed transactions (expensive, slower) | Rare (too expensive for webhooks) |
| At-most-once | No duplicates, but delivery not guaranteed | Simple webhook systems |
Why At-Least-Once?
At-least-once is the industry standard for webhooks because it maximizes reliability without the cost and complexity of distributed transactions. Implementing idempotency on the consumer side is much simpler and cheaper than exactly-once delivery.
Best Practices for Consumers
Follow these guidelines to handle at-least-once delivery correctly.
import { db } from './database';
async function handleWebhook(req, res) {
const { event_id, event_type, payload } = req.body;
// 1. Check if we've already processed this webhook
const existing = await db.query(
'SELECT id FROM processed_webhooks WHERE event_id = $1',
[event_id]
);
if (existing.rows.length > 0) {
console.log(`Webhook ${event_id} already processed - ignoring duplicate`);
return res.status(200).json({ status: 'already_processed' });
}
// 2. Process the webhook within a transaction
try {
await db.query('BEGIN');
// Process the event
if (event_type === 'user.created') {
await db.query(
'INSERT INTO users (id, email) VALUES ($1, $2)',
[payload.user_id, payload.email]
);
}
// 3. Mark as processed (prevents duplicates)
await db.query(
'INSERT INTO processed_webhooks (event_id, processed_at) VALUES ($1, NOW())',
[event_id]
);
await db.query('COMMIT');
// 4. Always return 2xx on success
res.status(200).json({ status: 'processed' });
} catch (error) {
await db.query('ROLLBACK');
// 5. Return 5xx for retryable errors
console.error('Failed to process webhook:', error);
res.status(500).json({ error: 'Processing failed' });
}
}- ✓Track processed webhooks - Store
event_idin a database to detect duplicates - ✓Use database transactions - Process webhook + mark as processed in a single atomic transaction
- ✓Return 2xx immediately - Respond quickly to avoid timeouts. Process asynchronously if needed.
- ✓Use timestamps for ordering - Don't assume webhooks arrive in order. Check timestamps to handle out-of-order delivery.
- ✓Clean up old records - Periodically delete
processed_webhooksolder than 30 days
Related Documentation
Idempotency →
Learn how to implement idempotent webhook handlers to handle duplicates
Retry Strategy →
Understand how Hook Mesh retries failed deliveries over 48 hours
Circuit Breaker →
See how the circuit breaker helps maintain delivery guarantees
Creating Jobs →
Create webhook jobs with idempotency keys to prevent duplicates