How Lettr Webhook Delivery Works
When an email event occurs, Lettr sends an HTTP POST request to your configured webhook endpoint. The delivery follows this sequence:- Event occurs (e.g., email is delivered)
- Lettr queues the webhook payload
- Lettr sends an HTTP POST to your endpoint URL
- Your server must respond with a
2xxstatus code within 30 seconds - If the request fails, Lettr retries with exponential backoff
What Counts as a Failure
| Response | Result |
|---|---|
2xx status code | Success — event is marked as delivered |
3xx redirect | Failure — Lettr does not follow redirects |
4xx status code | Failure — retried according to retry schedule |
5xx status code | Failure — retried according to retry schedule |
| Connection timeout (30s) | Failure — retried according to retry schedule |
| DNS resolution failure | Failure — retried according to retry schedule |
| TLS handshake failure | Failure — retried according to retry schedule |
Retry Logic and Schedule
When a webhook delivery fails, Lettr retries the request with exponential backoff:| Attempt | Delay After Previous Attempt |
|---|---|
| 1st retry | 1 minute |
| 2nd retry | 5 minutes |
| 3rd retry | 30 minutes |
| 4th retry | 2 hours |
| 5th retry | 8 hours |
Failed webhook events are visible in the Lettr dashboard under Webhooks > Event Log. You can manually retry individual failed events from this page.
Diagnosing Failures
Check the Webhook Event Log
The fastest way to diagnose webhook issues is the event log in the Lettr dashboard:- Go to Webhooks in the dashboard
- Click on the webhook endpoint that is failing
- Review the Event Log tab
- Click on a failed event to see the full request and response details, including:
- Request headers and body sent by Lettr
- Response status code and body returned by your server
- Error message (for connection-level failures)
Common Failure Patterns
All events failing with connection timeout
All events failing with connection timeout
Your server is taking longer than 30 seconds to respond.Fixes:
- Process webhook events asynchronously. Accept the request immediately (return
200), then process the event in a background job. - Check if your server is overloaded or if the webhook handler has a performance bottleneck.
- Verify your firewall allows inbound connections from Lettr’s IP ranges.
All events failing with DNS resolution error
All events failing with DNS resolution error
Lettr cannot resolve your webhook endpoint hostname.Fixes:
- Verify the URL in your webhook settings is correct.
- Check that your DNS records are properly configured and your domain is resolving.
- If you recently changed DNS providers, wait for propagation to complete.
All events failing with TLS error
All events failing with TLS error
The TLS handshake to your server is failing.Fixes:
- Verify your SSL certificate is valid and not expired.
- Ensure your server supports TLS 1.2 or higher.
- Check that the certificate chain is complete (intermediate certificates included).
Intermittent 5xx errors
Intermittent 5xx errors
Your server is sometimes returning 500-series errors.Fixes:
- Check your server logs around the time of the failed deliveries.
- Look for out-of-memory errors, database connection pool exhaustion, or unhandled exceptions in your webhook handler.
- Ensure your webhook handler is idempotent — it should handle receiving the same event more than once.
403 Forbidden responses
403 Forbidden responses
Your server is rejecting the request due to authentication or authorization rules.Fixes:
- If you have IP-based access controls, ensure Lettr’s sending IPs are allowlisted.
- If you require authentication headers, note that Lettr sends a
lettr-signatureheader — make sure your middleware isn’t blocking the request before signature verification. - Check for CSRF protection middleware intercepting the POST request.
Handling Timeouts
The 30-second timeout is the most common cause of webhook failures. Your webhook handler should return a response as quickly as possible.Recommended Architecture
Signature Verification
Every webhook request from Lettr includes alettr-signature header containing an HMAC-SHA256 signature of the request body. Always verify this signature to confirm the request is from Lettr.
Verification Steps
- Get the raw request body (unparsed)
- Compute an HMAC-SHA256 hash using your webhook secret
- Compare the computed hash with the
lettr-signatureheader value
Common Signature Verification Failures
| Problem | Cause | Fix |
|---|---|---|
| Signature always fails | Body parsed as JSON before verification | Use express.raw() on the webhook route |
| Wrong signature header name | Looking for x-signature instead of lettr-signature | Use the correct header: lettr-signature |
| Wrong secret | Using a secret from a different webhook endpoint | Each webhook endpoint has its own secret — check the dashboard |
| Timing-based failures | Using === instead of timingSafeEqual | Use crypto.timingSafeEqual() to prevent timing attacks |
Idempotency
Lettr may deliver the same webhook event more than once (due to retries or network issues). Your handler must be idempotent — processing the same event twice should not cause duplicate side effects.Implementing Idempotency
Use the event ID included in every webhook payload to deduplicate:Testing Webhooks
Before deploying to production, test your webhook endpoint to verify it handles events correctly.Using Lettr’s Test Events
Send test events from the Lettr dashboard:- Go to Webhooks and select your endpoint
- Click Send Test Event
- Select the event type to test
- Check your server logs and the event log to verify delivery