Skip to main content

Webhooks Not Received

Problem: Webhook events are not being delivered Quick Checks: Verify URL, HTTPS, response time, and network accessibility.
Ensure webhook URL is valid and accessible:
// Test webhook endpoint
const testPayload = { test: true };
const response = await fetch('https://your-server.com/webhooks/sessions', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(testPayload),
  signal: AbortSignal.timeout(10000) // 10s timeout
});

if (response.status !== 200) {
  console.log(`Webhook endpoint returned ${response.status}`);
} else {
  console.log('Webhook endpoint is accessible');
}
Webhook URLs must use HTTPS (HTTP will be rejected):
// ✅ Correct: HTTPS
const webhookUrl = "https://your-server.com/webhooks/sessions";

// ❌ Incorrect: HTTP (will be rejected)
// const webhookUrl = "http://your-server.com/webhooks/sessions";
Webhook endpoints must respond quickly (within 5 seconds):
// Your webhook handler should respond within 5 seconds
app.post('/webhooks/sessions', async (req, res) => {
  const payload = req.body;
  
  // Process asynchronously if needed
  setImmediate(() => processWebhook(payload));
  
  // Return immediately
  res.json({ status: 'received' }); // Must return 200 quickly
});
Ensure your server accepts incoming connections:
# Test if webhook URL is accessible from outside
http POST https://your-server.com/webhooks/sessions \
  Content-Type:application/json \
  test:=true

Duplicate Webhook Events

Problem: Receiving duplicate webhook events Solution: Implement idempotency with event tracking
// Track processed events
const processedEvents = new Map();

app.post('/webhooks/sessions', async (req, res) => {
  const payload = req.body;
  
  // Create unique event ID
  const eventId = `${payload.event}_${payload.session.id}_${payload.timestamp}`;
  
  // Check if already processed
  if (processedEvents.has(eventId)) {
    return res.json({ status: 'duplicate' });
  }
  
  // Process event
  await processWebhook(payload);
  
  // Mark as processed (keep for 1 hour)
  processedEvents.set(eventId, Date.now());
  
  // Cleanup old entries
  const oneHourAgo = Date.now() - 3600000;
  for (const [id, timestamp] of processedEvents.entries()) {
    if (timestamp < oneHourAgo) {
      processedEvents.delete(id);
    }
  }
  
  res.json({ status: 'received' });
});
Use a database or Redis for event tracking in production instead of in-memory storage for better reliability across multiple server instances.