Webhook Troubleshooting Guide
Solutions to common webhook problems and debugging strategies.
Debugging Toolsโ
Dashboard Delivery Attemptsโ
The BlockEden dashboard provides powerful debugging tools:
- Navigate to Accept Payments โ Webhooks
- Click on an endpoint to view its delivery attempts
- Expand any attempt to see:
- โ Full request body sent by BlockEden
- โ Full response body from your server
- โ HTTP status code
- โ Error messages
- โ Response time
- โ Retry schedule
Replay Failed Eventsโ
Don't worry if a webhook delivery fails - you can replay it:
- Find the failed attempt in the dashboard
- Click Replay Event button
- The event will be resent immediately
- Check if it succeeds this time
Test Your Endpointโ
Use the Test button to send a sample event:
- Click Test on your endpoint
- A
webhook.test.event
is sent with sample data - Verify your server receives and processes it correctly
- Check server logs and dashboard for results
Common Issuesโ
โ Issue: "Invalid Signature" (401 Unauthorized)โ
Symptoms:
- Your endpoint returns HTTP 401
- Logs show "Invalid signature" or "Unauthorized"
- All webhook deliveries fail with signature errors
Cause 1: Using Parsed JSON Instead of Raw Body
This is the most common mistake. You must verify the signature against the raw request body, not the parsed JSON.
// โ WRONG - Body is already parsed and modified
app.use(express.json());
app.post('/webhooks', (req, res) => {
const body = JSON.stringify(req.body); // This won't match!
const signature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
// Verification will fail
});
// โ
CORRECT - Use raw body
app.post('/webhooks',
express.raw({ type: 'application/json' }),
(req, res) => {
const body = req.body; // Raw Buffer
const signature = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
// Verification will succeed
}
);
Cause 2: Wrong Secret
You may be using an old secret or the wrong endpoint's secret.
Solution:
- Go to dashboard โ Click Rotate Secret on your endpoint
- Copy the new secret immediately (it's only shown once)
- Update your environment variable:
WEBHOOK_SECRET=your_new_secret
- Restart your server
- Click Test to verify it works
Cause 3: Whitespace or Encoding Issues
Ensure you're using the exact raw bytes without modification.
// Correct approach
const signature = crypto
.createHmac('sha256', secret)
.update(req.body) // Must be Buffer, not modified string
.digest('hex');
โฑ๏ธ Issue: Webhooks Timing Outโ
Symptoms:
- Dashboard shows "Timeout" errors
- No response received after 30 seconds
- Events are automatically retried
Cause 1: Endpoint Takes Too Long to Respond
Your handler is doing too much work synchronously.
// โ WRONG - Slow synchronous processing
app.post('/webhooks', async (req, res) => {
const event = parseAndVerify(req);
// This takes 60 seconds - too slow!
await processOrder(event);
await sendEmails(event);
await updateAnalytics(event);
res.status(200).send('OK'); // Too late - already timed out
});
// โ
CORRECT - Respond quickly, process async
app.post('/webhooks', async (req, res) => {
const event = parseAndVerify(req);
// Respond immediately (within 1 second)
res.status(200).json({ received: true });
// Process in background
processWebhookAsync(event).catch(err => {
console.error('Background processing error:', err);
// Log to error tracking service
});
});
async function processWebhookAsync(event) {
// Heavy processing here
await processOrder(event);
await sendEmails(event);
await updateAnalytics(event);
}
Cause 2: Endpoint Not Accessible
Your endpoint might be blocked by a firewall, behind a VPN, or using localhost.
Solutions:
- โ Ensure endpoint is publicly accessible over the internet
- โ Use HTTPS (HTTP is not supported)
- โ Check cloud provider security groups allow inbound HTTPS
- โ For local testing, use ngrok:
# Terminal 1: Start your server
npm start
# Terminal 2: Create secure tunnel
ngrok http 3000
# Output: Forwarding https://abc123.ngrok.io -> http://localhost:3000
# Use the ngrok HTTPS URL in BlockEden dashboard
๐ช Issue: Missing Webhooksโ
Symptoms:
- Some events aren't received
- Expected webhook never arrived
- Inconsistent delivery
Cause 1: Not Subscribed to Event Type
You're not subscribed to that specific event type.
Solution:
- Go to dashboard โ Edit your endpoint
- Check the boxes for event types you want to receive
- Click Save
Cause 2: Endpoint Disabled
The endpoint was automatically disabled due to repeated failures.
Solution:
- Check if endpoint shows "Disabled" badge in dashboard
- Review failure reason in delivery attempts table
- Fix the underlying issue (signature, timeout, etc.)
- Click Edit โ Toggle "Endpoint active" to re-enable
- Click Test to verify it works
Cause 3: Event Already Sent
BlockEden doesn't send duplicate events - this is correct behavior.
Solution: Each event is sent once per endpoint. Check your server logs or database to confirm if you actually processed it.
๐ Issue: Duplicate Event Processingโ
Symptoms:
- Same order fulfilled twice
- Customer charged multiple times
- Duplicate database records
Cause: Not Implementing Idempotency
Your handler doesn't check if an event was already processed.
// โ WRONG - No duplicate check
async function handleWebhook(event) {
// Process immediately without checking
await fulfillOrder(event.data.paymentId);
}
// โ
CORRECT - Check before processing
async function handleWebhook(event) {
// Check if already processed using event ID
const existing = await db.webhookEvents.findOne({
eventId: event.id
});
if (existing) {
console.log('Event already processed:', event.id);
return; // Skip duplicate
}
// Process the event
await fulfillOrder(event.data.paymentId);
// Mark as processed
await db.webhookEvents.create({
eventId: event.id,
type: event.type,
processedAt: new Date()
});
}
๐ซ Issue: "Connection Refused" Errorsโ
Symptoms:
- Dashboard shows "Connection refused"
- Error message: "Cannot connect to endpoint"
- Immediate failure (not timeout)
Cause 1: Server Not Running
Your webhook server is down or crashed.
Solution:
- โ
Check your server is running:
systemctl status your-service
- โ Verify it's listening on the correct port
- โ Check server logs for startup errors
- โ Use process manager like PM2 or systemd for auto-restart
Cause 2: Wrong URL or Port
The webhook URL doesn't match your actual endpoint.
Solution:
- โ Verify URL in dashboard matches your server
- โ
Check the path:
/webhooks
vs/webhook
vs/api/webhooks
- โ Ensure using HTTPS (HTTP not supported)
- โ Test with curl:
curl -X POST https://your-domain.com/api/webhooks \
-H "Content-Type: application/json" \
-d '{"test":"data"}'
Cause 3: Firewall Blocking Requests
Corporate firewall or cloud security group is blocking inbound traffic.
Solution:
- โ Allow incoming HTTPS traffic (port 443)
- โ Check cloud provider security groups (AWS, GCP, Azure)
- โ Verify network ACLs
- โ Contact support for BlockEden IP ranges to whitelist
๐ฅ Issue: 500 Internal Server Errorโ
Symptoms:
- Your endpoint returns HTTP 500
- BlockEden automatically retries the event
- Errors in your server logs
Cause 1: Unhandled Exception
Your code throws an error that crashes the request handler.
// โ WRONG - Unhandled errors crash the handler
app.post('/webhooks', async (req, res) => {
const event = parseAndVerify(req);
await processEvent(event); // If this throws, 500 is returned
res.status(200).send('OK');
});
// โ
CORRECT - Proper error handling
app.post('/webhooks', async (req, res) => {
try {
const event = parseAndVerify(req);
// Always return 200 first (even if processing fails)
res.status(200).json({ received: true });
// Process with error handling
await processEvent(event);
} catch (error) {
console.error('Webhook processing error:', error);
// Log to error tracking service (Sentry, Datadog, etc.)
// Don't throw - webhook was already acknowledged
}
});
Cause 2: Database Connection Error
Can't connect to your database.
Solution:
- โ Check database is running and accessible
- โ Verify connection string
- โ Check network connectivity
- โ Handle database errors gracefully:
try {
await db.orders.create(orderData);
} catch (dbError) {
console.error('Database error:', dbError);
// Still return 200 - retry won't help DB issues
}
๐ฆ Issue: Events Out of Orderโ
Symptoms:
- Receive
payment.confirmed
beforepayment.pending
- Events arrive in unexpected sequence
- State transitions seem wrong
Cause: Network Delays or Retries
Events may arrive out of order due to network conditions or retries.
Solution: Use Status Field, Not Event Order
Don't rely on event arrival order. Always check the current status:
async function handlePaymentEvent(event) {
const payment = event.data;
// Get current status from your database
const existingPayment = await db.payments.findOne({
id: payment.paymentId
});
// Only update if new status is "higher" than current
const statusPriority = {
'pending': 1,
'confirmed': 2,
'failed': 3,
'refunded': 4
};
if (statusPriority[payment.status] > statusPriority[existingPayment.status]) {
await db.payments.update(payment.paymentId, {
status: payment.status,
updatedAt: new Date()
});
} else {
console.log('Ignoring older event:', event.type);
}
}
Best Practicesโ
โ 1. Always Verify Signaturesโ
Never skip signature verification:
const signature = req.headers['x-eden-signature'];
if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
return res.status(401).send('Unauthorized');
}
โ 2. Return 200 Within 1 Secondโ
Acknowledge receipt immediately:
// Return 200 in < 1 second
res.status(200).json({ received: true });
// Process in background (can take minutes)
processAsync(event);
โ 3. Handle Idempotencyโ
Prevent duplicate processing:
if (await alreadyProcessed(event.id)) {
console.log('Duplicate event, skipping');
return;
}
โ 4. Log Everythingโ
Comprehensive logging helps debugging:
console.log('Webhook received:', {
eventId: event.id,
type: event.type,
paymentId: event.data.paymentId,
status: event.data.status,
timestamp: new Date().toISOString()
});
โ 5. Monitor Failuresโ
Set up alerts for webhook failures:
- Check dashboard regularly
- Set up alerts for high failure rates (>10%)
- Replay failed events after fixing issues
- Monitor success rate badge on endpoints
โ 6. Handle Unknown Eventsโ
New event types may be added in the future:
switch (event.type) {
case 'payment.confirmed':
await handlePaymentConfirmed(event.data);
break;
case 'payment.failed':
await handlePaymentFailed(event.data);
break;
default:
// Log but don't fail for unknown event types
console.log('Unknown event type:', event.type);
}
Pre-Launch Testing Checklistโ
Before going live, verify your webhook endpoint:
- โ Can receive test webhook from dashboard
- โ Signature verification works correctly
- โ Returns 200 OK within 1 second
- โ Logs event details for debugging
- โ Handles unknown event types gracefully
- โ Doesn't process same event twice (idempotency)
- โ Works with production HTTPS URL
- โ Error handling doesn't crash server
- โ Background processing completes successfully
- โ Database updates work correctly
Local Development Testingโ
Using ngrokโ
# Terminal 1: Start your development server
npm run dev
# Terminal 2: Create secure tunnel
ngrok http 3000
# Output:
# Forwarding https://abc123.ngrok.io -> http://localhost:3000
# Use the ngrok HTTPS URL in BlockEden dashboard
Using localtunnelโ
# Start your server
npm start
# Create tunnel (no account needed)
npx localtunnel --port 3000
# Output: your url is: https://random-name.loca.lt
# Use this URL in BlockEden dashboard
Getting Helpโ
Dashboard Debuggingโ
Use the dashboard's built-in debugging tools:
- View Delivery Attempts - See full request/response details
- Check Failure Reasons - Understand why deliveries failed
- Replay Failed Events - Resend events after fixing issues
- Test Endpoint - Send sample events manually
Check Server Logsโ
Always check your server logs for errors:
# For PM2
pm2 logs your-app-name
# For systemd
journalctl -u your-service-name -f
# For Docker
docker logs container-name -f
Contact Supportโ
If you're still stuck, contact support with:
Email: support@blockeden.xyz
Include:
- Endpoint ID from dashboard
- Event ID (from failed delivery)
- Error message from your server logs
- Delivery attempt details from dashboard (screenshot)
- Your webhook handler code (without secrets)
Response Time: Usually within 24 hours
Community Supportโ
- Forum: https://blockeden.xyz/forum
- Discord: https://discord.gg/eWZvE4RSBw
- GitHub Discussions: Share integration examples
Next Stepsโ
- ๐ Learn More: Read the Quick Start Guide
- ๐ Security: Review Signature Verification
- ๐ Events: Check Event Reference for all event types
- ๐ Overview: Back to Webhooks Overview