Handling Webhooks
Best practices for receiving and processing webhook events reliably.
Retry Behavior
When webhook delivery fails, Araucaria automatically retries with exponential backoff:
| Attempt | Delay After Failure |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 (final) | 24 hours |
After 5 failed retries, the delivery is marked as permanently failed.
Success Response
A webhook delivery is considered successful when your endpoint returns HTTP status 2xx (200-299).
What Triggers a Retry
- Your endpoint returns a non-2xx status code (4xx, 5xx)
- The request times out (30 second timeout)
- A network error occurs (DNS failure, connection refused, etc.)
Idempotency
Webhooks are delivered with at-least-once semantics, meaning you may receive
the same event multiple times. Always use the id field to deduplicate:
javascript
async function handleWebhook(event) {
// Check if already processed
const existing = await db.processedEvents.findOne({
eventId: event.id
});
if (existing) {
console.log('Event already processed, skipping');
return;
}
// Process the event
await processEvent(event);
// Mark as processed
await db.processedEvents.insert({
eventId: event.id,
processedAt: new Date()
});
}
Respond Quickly
Return a 200 response as quickly as possible. If processing takes time,
acknowledge the webhook first and process asynchronously:
javascript
app.post('/webhooks/araucaria', async (req, res) => {
// Verify signature first
if (!verifySignature(req)) {
return res.status(401).send('Invalid signature');
}
// Acknowledge immediately
res.status(200).send('OK');
// Process asynchronously (don't await)
queueForProcessing(req.body);
});
Best Practices
Security
- Always verify signatures - Never process webhooks without verification
- Use HTTPS - Webhook endpoints must use TLS encryption
- Keep secrets secure - Store webhook secrets in environment variables
Reliability
- Implement idempotency - Use event IDs to prevent duplicate processing
- Respond quickly - Return 200 within a few seconds
- Process asynchronously - Queue events for background processing
- Handle all event types - Even if you ignore some, acknowledge with 200
Monitoring
- Log all receipts - Track event IDs, types, and processing status
- Monitor for failures - Alert on repeated verification failures
- Track processing time - Ensure handlers complete within timeout
💡 Testing Locally
Use a tunneling service like ngrok to expose your local endpoint for testing:
ngrok http 3000