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