Webhook Best Practices
This guide covers essential patterns for implementing reliable, secure, and scalable webhook handlers.
1. Respond Quickly
Your endpoint must respond within 20 seconds. Aim for under 1 second by acknowledging immediately and processing asynchronously.
✅ Recommended Pattern
app.post("/webhooks/trst", async (req, res) => {
try {
verifySignature(req, process.env.TRST_WEBHOOK_SECRET)
const event = JSON.parse(req.body.toString())
// Acknowledge IMMEDIATELY
res.status(200).send("OK")
// Process asynchronously (don't await!)
processWebhookEvent(event).catch((error) => {
logger.error("Webhook processing failed", {
error: error.message,
eventId: event.event_id,
})
})
} catch (error) {
logger.error("Webhook verification failed", { error: error.message })
res.status(401).send("Unauthorized")
}
})
async function processWebhookEvent(event) {
// Now you have time to do slow operations
await updateDatabase(event.data)
await sendNotifications(event.data)
await callExternalAPI(event.data)
}For high-volume webhooks, use a message queue (Redis, RabbitMQ, etc.) to decouple receipt from processing.
2. Handle Duplicates (Idempotency)
You may receive the same event multiple times. Always check event_id before processing.
3. Handle Unknown Event Types
Your endpoint may receive new event types we add in the future. Always handle unknown events gracefully.
function handleEvent(event) {
switch (event.event_type) {
case "enrollment.completed":
return handleEnrollment(event.data)
case "demo.scan.success":
return handleScan(event.data)
case "webhook.test":
logger.info("Test webhook received")
return Promise.resolve()
default:
// Don't crash - log and ignore
logger.warn("Unknown event type (ignoring)", {
eventType: event.event_type,
eventId: event.event_id,
})
return Promise.resolve()
}
}4. Implement Error Handling
Catch errors to prevent crashes and avoid exposing internal details.
app.post("/webhooks/trst", async (req, res) => {
try {
verifySignature(req, process.env.TRST_WEBHOOK_SECRET)
const event = JSON.parse(req.body.toString())
logger.info("Webhook received", {
eventId: event.event_id,
eventType: event.event_type,
})
res.status(200).send("OK")
processWebhookEvent(event).catch((error) => {
logger.error("Processing failed", {
eventId: event.event_id,
error: error.message,
})
})
} catch (error) {
logger.error("Verification failed", { error: error.message })
res.status(401).send("Unauthorized")
}
})5. Secure Your Endpoint
Always Verify Signatures
See the Security Guide for complete verification implementation.
IP Allowlisting (Coming Soon)
IP Allowlist Not Yet Available
TRST has not yet published webhook source IP ranges. IP allowlisting will be available in a future update. For now, rely on HMAC signature verification for security.
Contact support if you need IP ranges for your security requirements.
6. Monitor Your Webhooks
Track key metrics to detect issues early:
- Success rate - Percentage of successful webhook processing
- Error rate - Failed processing attempts
- Processing time - How long events take to process
- Pending deliveries - Backlog of undelivered webhooks
// Basic monitoring example
async function checkWebhookHealth(webhookId) {
const deliveries = await getRecentDeliveries(webhookId, { limit: 10 })
const failures = deliveries.filter((d) => d.status === "failed")
if (failures.length > 3) {
await sendAlert({
message: "High webhook failure rate",
failures: failures.length,
})
}
}7. Test Before Production
Always test webhooks in a staging environment:
- [ ] Use real HTTPS endpoint (not localhost)
- [ ] Verify signature verification works
- [ ] Test duplicate event handling
- [ ] Test all event types
- [ ] Monitor logs for errors
Use the test endpoint to verify your integration:
curl -X POST https://api.prod.trstinc.ca/v1/project/{project_id}/webhooks/{webhook_id}/test \
-H "Authorization: Bearer YOUR_API_KEY"8. Handle Downtime
Plan for webhook endpoint downtime.
Production Checklist
Before going live:
Security
- [ ] Signature verification implemented
- [ ] Secrets stored securely (environment variables or secrets manager)
- [ ] HTTPS endpoint with valid certificate
- [ ] Rate limiting configured
- [ ] Error messages don't expose internal details
Reliability
- [ ] Responds within 1-2 seconds
- [ ] Async processing (queue or background jobs)
- [ ] Duplicate detection using
event_id - [ ] Handles unknown event types gracefully
- [ ] Comprehensive error handling and logging
Monitoring
- [ ] Log all webhook events
- [ ] Track success/error rates
- [ ] Alert on high error rates
- [ ] Monitor pending deliveries
Testing
- [ ] Tested in staging environment
- [ ] Test webhook endpoint verified
- [ ] All event types handled
- [ ] Failure scenarios tested
Quick Tips
DO:
- ✅ Respond with 200 OK immediately
- ✅ Process events asynchronously
- ✅ Check
event_idfor duplicates - ✅ Verify HMAC signature on every request
- ✅ Log all webhook events
- ✅ Handle unknown event types gracefully
DON'T:
- ❌ Process events synchronously before responding
- ❌ Skip duplicate checking
- ❌ Skip signature verification
- ❌ Crash on unknown event types
- ❌ Expose internal errors in responses
- ❌ Use HTTP (must use HTTPS)
Next Steps
- Event Reference - Webhook payload schemas
- Security Guide - Signature verification implementation
- Testing Guide - Debugging and testing strategies
- API Reference - Webhook management endpoints