Documentation

Complete guide to webhooks, debugging, and real-time event monitoring with HookMetry

Webhook Retry Logic

Most webhook providers automatically retry failed webhook deliveries. Understanding retry behavior is crucial for building reliable integrations.

Common Retry Patterns

Exponential Backoff (Most Common)

Retry delays increase exponentially: 1s 2s 4s 8s 16s...

  • • Used by: Stripe, GitHub, most modern APIs
  • • Attempts: Usually 3-10 retries over hours/days
  • • Prevents: Server overload during outages

Fixed Interval

Retry at regular intervals: every 5 minutes, every hour, etc.

  • • Simpler but less efficient
  • • Can overwhelm failing servers

Best Practices for Handling Retries

DO:

  • • Return HTTP 200 only when successfully processed
  • • Store event IDs to detect and skip duplicates
  • • Use database transactions for atomic operations
  • • Implement idempotent handlers (safe to run multiple times)

DON'T:

  • • Return 200 before processing (may lose events on crash)
  • • Process the same event multiple times without checks
  • • Rely on webhooks arriving in order
  • • Block the response with slow operations

Example: Idempotent Webhook Handler (Node.js)

// Using Redis for deduplication
const redis = require('redis');
const client = redis.createClient();

async function handleWebhook(req, res) {
  const eventId = req.body.id;
  
  // Check if we've already processed this event
  const processed = await client.get(`webhook:${eventId}`);
  if (processed) {
    console.log('Duplicate webhook, skipping:', eventId);
    return res.status(200).json({ message: 'Already processed' });
  }
  
  try {
    // Process the webhook
    await processPayment(req.body);
    
    // Mark as processed (expires after 7 days)
    await client.setex(`webhook:${eventId}`, 604800, 'processed');
    
    res.status(200).json({ message: 'Processed successfully' });
  } catch (error) {
    console.error('Processing failed:', error);
    // Return 5xx to trigger retry
    res.status(500).json({ error: 'Processing failed' });
  }
}