Skip to content

Webhook Best Practices

Follow these patterns to build reliable, secure, and maintainable webhook integrations.

Respond Quickly

Webhook providers expect a fast response. If your processing takes more than a few seconds, accept the webhook immediately and process it asynchronously.

Do this:

javascript
// Accept the webhook, process later
app.post('/webhook', async (req, res) => {
  await queue.enqueue(req.body);
  res.status(200).json({ received: true });
});

Don't do this:

javascript
// Blocks the response until processing completes
app.post('/webhook', async (req, res) => {
  await processOrder(req.body);      // 10+ seconds
  await updateInventory(req.body);   // 5+ seconds
  await notifyCustomer(req.body);    // 3+ seconds
  res.status(200).json({ done: true });
});

Hookbase enforces a 30-second timeout. Destinations that consistently time out will trigger circuit breaker protection.

Implement Idempotency

Webhooks may be delivered more than once due to retries, network issues, or provider behavior. Your handler should produce the same result whether it processes an event once or multiple times.

Use Event IDs

Most providers include a unique event ID. Store processed IDs and skip duplicates:

javascript
app.post('/webhook', async (req, res) => {
  const eventId = req.headers['x-hookbase-event-id'];

  // Check if already processed
  const exists = await db.get('SELECT 1 FROM processed_events WHERE event_id = ?', eventId);
  if (exists) {
    return res.status(200).json({ duplicate: true });
  }

  // Process and record
  await processEvent(req.body);
  await db.run('INSERT INTO processed_events (event_id) VALUES (?)', eventId);

  res.status(200).json({ processed: true });
});

Hookbase Deduplication

Hookbase can deduplicate events at the platform level before they reach your destination. Enable deduplication on your source to filter out duplicates automatically.

Verify Signatures

Always verify webhook signatures to ensure the payload hasn't been tampered with. Hookbase verifies signatures on inbound webhooks automatically, but you should also verify the delivery signature from Hookbase to your destination.

javascript
import crypto from 'crypto';

function verifyHookbaseSignature(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

app.post('/webhook', (req, res) => {
  const signature = req.headers['x-hookbase-signature'];
  if (!verifyHookbaseSignature(req.rawBody, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }
  // Process webhook...
});

TIP

Use crypto.timingSafeEqual() to prevent timing attacks when comparing signatures.

Handle Retries Gracefully

Hookbase retries failed deliveries with exponential backoff. Design your handler to work well with retries:

  1. Return proper status codes — Use 200-299 for success, 4xx for permanent errors (won't retry), 5xx for temporary errors (will retry)
  2. Be idempotent — Same event processed twice should have the same outcome
  3. Log the attempt — Include the x-hookbase-delivery-id header in your logs for tracing
Response CodeHookbase Behavior
200-299Success, no retry
400-499Permanent failure, no retry
500-599Temporary failure, will retry
TimeoutWill retry
Connection errorWill retry

Use Transforms to Simplify Handlers

Instead of parsing complex provider payloads in your application, use transforms to extract only the fields you need:

jsonata
{
  "event": type,
  "customer_email": data.object.customer_email,
  "amount": data.object.amount_total / 100,
  "currency": data.object.currency
}

This reduces your handler complexity and keeps your application code focused on business logic.

Apply Filters to Reduce Noise

Don't process webhooks you don't need. Use filters to only deliver relevant events:

jsonata
type in ["checkout.session.completed", "invoice.paid", "customer.subscription.deleted"]

Filtering at the platform level reduces load on your application and keeps your event processing focused.

Monitor Delivery Health

Set Up Notification Channels

Configure notification channels to alert you when:

  • Delivery failure rate exceeds a threshold
  • A destination becomes unreachable
  • The circuit breaker opens

Track Key Metrics

Use the Analytics API to monitor:

  • Delivery success rate — Should stay above 99%
  • Average delivery latency — Watch for increasing trends
  • Queue depth — Growing queues indicate destination problems
  • Error distribution — Identify the most common failure modes

Check Health Status

Poll the Health API from your monitoring system to detect platform-level issues early.

Secure Your Webhooks

Use HTTPS Destinations

Always use https:// URLs for your destinations. Hookbase rejects http:// destinations in production to prevent payload interception.

Restrict Source IPs

Configure IP filtering to only accept webhooks from known provider IP ranges. Most providers publish their webhook IP ranges.

Enable Field Encryption

For sensitive data (PII, payment details), enable field-level encryption to encrypt specific fields before storage and delivery.

Rotate Secrets Regularly

Rotate your signing secrets periodically using the Sources API:

bash
curl -X POST https://api.hookbase.app/api/organizations/{orgId}/sources/{src_id}/rotate-secret \
  -H "Authorization: Bearer whr_your_api_key"

Update the new secret in your provider's dashboard immediately after rotation.

Plan for Failure

Configure Failover Destinations

Set up failover destinations so webhooks are delivered to a backup endpoint if your primary destination goes down.

Use the Dead Letter Queue

Events that exhaust all retry attempts land in the dead letter queue. Monitor the DLQ and set up a process to review and reprocess failed events.

Test Your Error Handling

Simulate failures during development:

  • Return 500 from your destination to test retries
  • Shut down your destination to test circuit breaker behavior
  • Send malformed payloads to test your validation

Production Readiness Checklist

Before going live, verify:

  • [ ] Signature verification is enabled on all sources
  • [ ] Destinations use HTTPS
  • [ ] Handlers are idempotent
  • [ ] Handlers respond within 30 seconds
  • [ ] Notification channels are configured for failures
  • [ ] Failover destinations are set up for critical routes
  • [ ] IP filtering is configured where applicable
  • [ ] Secrets are stored securely (not hardcoded)
  • [ ] Monitoring dashboards are in place

See the Production Readiness guide for a comprehensive checklist.

See Also

Released under the MIT License.