Dead Letter Webhook Recovery Proxy
Dead Letter is a high-availability webhook ingestion gateway. It sits between external webhook providers (like Stripe, Shopify, GitHub) and your application server. If your application server goes down, database operations lock up, or rate limits are exceeded, Dead Letter intercepts the failing payloads, stores them securely in a Dead Letter Queue (DLQ), and handles automatic or manual retries.
General Integration Steps
1. Create Endpoint
Go to your Dead Letter console, navigate to Endpoints, and click 'Create Endpoint'. Provide your target URL (e.g., https://my-app.com/api/webhooks).
2. Obtain Ingestion Slug & HMAC Secret
Copy your new endpoint's Ingestion URL (containing the slug) and the generated HMAC Secret Key. The Ingestion URL will serve as the webhook target.
3. Update Third-Party Provider Settings
Paste the Dead Letter Ingestion URL into your webhook provider settings page (Stripe, Shopify, or GitHub) as the destination endpoint.
Configure Webhook Providers
Configure your service providers to direct events to your Dead Letter ingestion proxy.
Stripe Webhook Configuration
- Navigate to your Stripe Webhook Dashboard .
- Click the Add endpoint button in the top right.
- In the Endpoint URL field, paste your Dead Letter Ingestion URL:
https://api.deadletterhub.io/ingest/<your-slug>. - Select the event types you want to forward (e.g.,
charge.succeeded,customer.subscription.deleted). - Save the configuration. You are ready to intercept events.
Shopify App Webhooks
- Log in to your Shopify Admin page and navigate to Settings > Notifications.
- Scroll down to the Webhooks section and click Create webhook.
- Select the Event type (e.g.,
Order creation). - Ensure the format is set to JSON.
- In the URL input, paste your Dead Letter Ingestion URL.
- Select the latest webhook API version and click Save.
GitHub Webhooks
- Open your Repository on GitHub, click Settings, and choose Webhooks.
- Click Add webhook in the top right.
- Paste your Ingestion URL into the Payload URL field.
- Set the Content type dropdown to
application/json. - Choose the events you want to trigger the webhook (e.g.,
push,pull_request). - Ensure the webhook checkbox is marked Active and click Add webhook.
Signature Verification
To secure your destination endpoints from unauthorized requests, Dead Letter signs all forwarded webhook payloads using your endpoint's unique secret key. This signature is computed using a HMAC SHA-256 hashing algorithm over the raw request payload body and is sent in the headers as:
Timing Attacks Protection
When verifying the signature, avoid using standard string equality operators (like == or ===). Standard comparisons exit early when a mismatch is found, leaking execution time variations that allow attackers to guess the signature byte-by-byte. Always use constant-time comparison functions.
Verification Code Snippets
Copy and integrate these secure verification functions directly into your webhook route handlers.
const crypto = require('crypto');
/**
* Verifies the signature of a webhook payload sent by Dead Letter.
*
* @param {string|object} payload - The raw request body string or parsed JSON object.
* @param {string} signature - The signature from the 'x-dead-letter-signature' header.
* @param {string} secretKey - The endpoint's HMAC Secret Key.
* @returns {boolean} - True if signature is valid, false otherwise.
*/
function verifySignature(payload, signature, secretKey) {
const payloadString = typeof payload === 'string'
? payload
: JSON.stringify(payload);
const computedSignature = crypto
.createHmac('sha256', secretKey)
.update(payloadString)
.digest('hex');
// Prevent timing attacks using timingSafeEqual
const signatureBuffer = Buffer.from(signature, 'hex');
const computedBuffer = Buffer.from(computedSignature, 'hex');
if (signatureBuffer.length !== computedBuffer.length) {
return false;
}
return crypto.timingSafeEqual(signatureBuffer, computedBuffer);
}API Key Management
Dead Letter supports programmatic API access via workspace-level API keys. You can create, rotate, and revoke keys from the API Keys page in the dashboard.
Key Prefixes and Permissions
| Prefix | Role | Permissions |
|---|---|---|
| dl_live_ | Read-Write | Create, update, delete endpoints; view and retry events; manage alerts |
| dl_read_ | Read-Only | View endpoints, event logs, and analytics; no mutations allowed |
Authentication
Include the API key in the Authorization header of your requests:
Authorization: Bearer dl_live_abc123def456...Key Rotation and Revocation
To rotate a key, create a new key in the dashboard, update your applications to use the new key, then revoke the old key. Revoked keys are immediately invalidated and cannot be restored. We recommend rotating keys every 90 days as a security best practice.
Rate Limiting
Dead Letter applies rate limits at multiple levels to protect the ingestion pipeline from abuse and ensure fair resource allocation across tenants.
Per-Second Limits (Ingestion)
| Tier | Limit |
|---|---|
| Free | 10 req/s |
| Pro | 100 req/s |
| Enterprise | 500 req/s |
Monthly Volume Caps
| Tier | Limit |
|---|---|
| Free | 100,000 events/mo |
| Pro | 1,000,000 events/mo |
| Enterprise | Unlimited |
IP-Level Rate Limiting
A global IP-based rate limit of 100 requests per second is applied to the ingestion endpoint before any workspace-level checks. This protects against attacks targeting invalid slugs.
Response Headers
Every ingestion response includes rate limit headers so you can monitor and manage your usage programmatically:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Workspace per-second rate limit |
| X-RateLimit-Remaining | Requests remaining in the current second window |
| X-Monthly-Events-Limit | Monthly event cap |
| X-Monthly-Events-Count | Events used this month |
| X-IP-RateLimit-Limit | IP-level per-second rate limit |
| X-IP-RateLimit-Remaining | IP requests remaining in the current window |
Handling 429 Responses
When you receive a 429 Too Many Requests response, back off and retry after a short delay. Check the X-RateLimit-Remaining header to gauge when the window resets. For monthly cap violations, a 402 Payment Required is returned with a link to upgrade your tier.
Webhook Event Lifecycle
Every webhook payload that reaches Dead Letter follows a defined lifecycle through the ingestion, queue, and delivery pipeline.
Delivery Flow
POST /ingest→202 Accepted→PENDING
First attempt→SUCCESS(delivered)
Failure (5xx / timeout)→Retry queue
Retry 1 (1 min)→SUCCESSorschedule next
Retry N (8h + backoff)→FAILED (DLQ)
Manual retry→PENDING→SUCCESSorFAILED
Retry Schedule
Failed deliveries are retried at the following intervals, with a maximum of 8 attempts:
Event Statuses
PENDING — Queued for delivery or retry
SUCCESS — Successfully delivered (2xx response)
FAILED — All retries exhausted, moved to DLQ
Delivery Guarantees
Dead Letter provides at-least-once delivery. Each webhook is delivered at least once; under error conditions (network failures, worker crashes), duplicate delivery is possible. Use the x-dead-letter-event-id header to deduplicate on your destination server.
API Error Codes
The Dead Letter ingestion API uses standard HTTP response codes to indicate success or failure. All error responses include a JSON body with an error field describing the issue.
| Code | Meaning | Action |
|---|---|---|
| 202 | Accepted | Webhook received and queued for delivery. No further action needed. |
| 400 | Bad Request | Invalid payload format or missing required fields. Check the error message for details and fix the request. |
| 401 | Unauthorized | API key or authentication token is missing, invalid, or expired. Check your Authorization header. |
| 402 | Payment Required | Monthly ingestion volume cap exceeded. Visit your billing page to upgrade your workspace tier. |
| 404 | Not Found | No endpoint matches the provided ingestion slug. Verify the slug in your Dead Letter dashboard. |
| 413 | Payload Too Large | Payload exceeds the maximum allowed body size. Reduce payload size and retry. |
| 429 | Too Many Requests | Per-second rate limit exceeded for this workspace or IP. Wait for the window to reset. |
| 500 | Internal Error | An unexpected server error occurred. Dead Letter will attempt to retry automatically. |