Webhook Reliability API
Webhook Reliability guarantees delivery of every event to every registered endpoint — with exponential retry, cryptographic signing, and a full audit log per delivery.
What is it?
Webhook Reliability guarantees delivery of every event to every registered endpoint — with exponential retry, cryptographic signing, and a full audit log per delivery. It accepts a single JSON payload and returns a structured response in milliseconds — no agents, plugins, or background workers required. The API is designed for synchronous, real-time use: call it inline in your request handler, CI step, or event pipeline and act on the result immediately.
Why do you need it?
Problem
- Webhooks silently fail when the destination is down, slow, or returns non-2xx — you have no idea what was missed.
- Providers retry a handful of times and then give up, leaving your system in an inconsistent state with no record.
- Debugging missed webhooks requires scraping provider dashboards and manually correlating timestamps.
Consequence
- Missed order.paid events mean unfulfilled shipments and angry customers — each missed event can cost $50–$500 in manual remediation.
- Missed subscription.cancelled events result in continued charging and potential fraud chargebacks.
- Missed user.deleted events leave PII in your system past its retention window — a GDPR violation with fines up to €20M.
Solution
- Reliable delivery with 8-attempt exponential backoff over 24 hours — your endpoint can be down for hours and nothing is lost.
- Full replay capability: re-deliver any event from the last 30 days with a single API call.
- HMAC-SHA256 signed payloads so every endpoint can verify the event is authentic before processing.
Use cases
E-commerce order fulfillment
Ingest payment provider webhooks and fan out to your fulfillment service. If fulfillment is temporarily down, the retry schedule ensures the order is processed when it recovers.
Node.js — ingest and fan out
const API_KEY = process.env.DEVOPSIL_API_KEY;
// Ingest a payment webhook and route to fulfillment
const result = await fetch('https://devopsil.com/api/v1/webhooks/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_type: 'order.paid',
payload: { order_id: 'ord_9k2x', amount: 4999, currency: 'USD' },
destinations: ['https://fulfillment.internal/webhooks'],
idempotency_key: 'pay_abc123',
}),
}).then(r => r.json());Use result.delivery_id to track status. If fulfillment fails, the API retries on schedule — no code needed.
Multi-tenant SaaS notifications
Deliver events to each customer's registered endpoint independently. One slow or failed customer endpoint never affects delivery to others.
Node.js — multi-tenant fan-out
const API_KEY = process.env.DEVOPSIL_API_KEY;
const result = await fetch('https://devopsil.com/api/v1/webhooks/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_type: 'subscription.upgraded',
payload: { tenant_id: 'ten_77z', plan: 'pro' },
destinations: tenantEndpoints, // array of customer webhook URLs
idempotency_key: `sub_upgrade_${tenantId}`,
}),
}).then(r => r.json());Each destination gets independent retry tracking. Check result.destinations[n].status to see per-tenant delivery state.
Audit trail / compliance log
Every delivery attempt is logged with timestamp, HTTP status, latency, and response body. Query the audit log for compliance reporting or incident investigation.
Node.js — fetch delivery log
const API_KEY = process.env.DEVOPSIL_API_KEY;
const log = await fetch(
'https://devopsil.com/api/v1/webhooks/deliveries?delivery_id=dlv_x9m2k',
{
headers: { Authorization: `Bearer ${API_KEY}` },
}
).then(r => r.json());
// log.attempts = [{attempt: 1, status: 503, ts: '...', latency_ms: 234}, ...]Export log.attempts to your audit store. Each attempt has HTTP status, response snippet, and latency.
Event replay after outage
When a downstream service recovers after an outage, replay all events it missed without re-triggering the original source.
Node.js — replay window
const API_KEY = process.env.DEVOPSIL_API_KEY;
const replay = await fetch('https://devopsil.com/api/v1/webhooks/replay', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
destination: 'https://fulfillment.internal/webhooks',
from_ts: '2024-03-10T02:00:00Z',
to_ts: '2024-03-10T08:30:00Z',
event_types: ['order.paid', 'order.refunded'],
}),
}).then(r => r.json());replay.queued_count tells you how many events were re-queued. They deliver with the same retry guarantees as fresh events.
Signature verification middleware
Verify HMAC-SHA256 on inbound webhooks from any provider before your handlers process them, using the same verification endpoint.
Node.js — verify inbound signature
const API_KEY = process.env.DEVOPSIL_API_KEY;
// In your Express middleware
const verify = await fetch('https://devopsil.com/api/v1/webhooks/verify', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
payload: rawBody, // raw string, not parsed
signature: req.headers['x-signature'],
secret: process.env.WEBHOOK_SECRET,
}),
}).then(r => r.json());
if (!verify.valid) return res.status(401).send('Invalid signature');Only continue processing if verify.valid is true. Logs a tamper attempt if the signature doesn't match.
Dead letter queue monitoring
Get alerted when an endpoint accumulates consecutive failures, and inspect the last error before attempting manual intervention.
Node.js — check dead letter queue
const API_KEY = process.env.DEVOPSIL_API_KEY;
const dlq = await fetch(
'https://devopsil.com/api/v1/webhooks/dead-letters?min_failures=5',
{
headers: { Authorization: `Bearer ${API_KEY}` },
}
).then(r => r.json());
for (const entry of dlq.endpoints) {
await alertSlack(`DLQ: ${entry.url} failed ${entry.consecutive_failures}x`);
}Each dlq.endpoints entry has url, consecutive_failures, last_error, and last_attempt_ts. Page on-call when count > 0.
Delivery guarantees
| Feature | Value |
|---|---|
| Max retry attempts | 8 |
| Retry schedule | 1m, 5m, 15m, 1h, 2h, 4h, 8h, 24h |
| Signature algorithm | HMAC-SHA256 |
| Payload replay window | 30 days |
| Delivery timeout | 30 seconds |
| Event pattern matching | Exact, prefix wildcard (order.*), global (*) |
| Idempotency | Deduplication by idempotency_key |
| Max payload size | 1 MB |
How the API works
All requests use Bearer authentication. Your API key starts with weh_. Get one at /dashboard/api-keys.
Request
{
"event_type": "order.paid",
"payload": {
"order_id": "ord_9k2x",
"amount": 4999,
"currency": "USD",
"customer_email": "[email protected]"
},
"destinations": ["https://fulfillment.acme.com/webhooks"],
"idempotency_key": "pay_abc123_evt_001"
}Response
{
"delivery_id": "dlv_x9m2kp3z",
"event_type": "order.paid",
"status": "queued",
"destinations": [
{
"url": "https://fulfillment.acme.com/webhooks",
"status": "pending",
"attempt": 0,
"next_attempt_at": "2024-03-15T14:00:02Z"
}
],
"signed": true,
"idempotency_key": "pay_abc123_evt_001",
"created_at": "2024-03-15T14:00:00Z"
}Quick start
Get your API key
Create a free account and generate a key at /dashboard/api-keys. Your key starts with weh_.
Make your first call
Node.js
const API_KEY = process.env.DEVOPSIL_API_KEY; // starts with weh_
const result = await fetch('https://devopsil.com/api/v1/webhooks/events', {
method: 'POST',
headers: {
Authorization: `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
event_type: 'order.paid',
payload: { order_id: 'ord_001', amount: 1999 },
destinations: ['https://your-server.com/webhooks'],
idempotency_key: 'test_event_001',
}),
}).then(r => r.json());
console.log(result.delivery_id, result.status);Act on the result
Node.js — handle response
if (result.status === 'queued') {
console.log('Event queued for delivery:', result.delivery_id);
// Poll GET /webhooks/deliveries?delivery_id=... to check status
} else {
console.error('Unexpected status:', result.status, result.error);
}