Overview
Monitor webhook deliveries to debug issues, track success rates, and ensure your integration is working correctly.
Authentication
Requires Platform API Key in the X-API-Key header.
Request
GET https://api.syncline.run/v1/platform/webhook/logs
Query Parameters
Number of delivery records to return (default: 50, max: 200)
Filter by event type (e.g., “meeting.scheduled”, “user.calendar_connected”)
Filter by status: “success” or “failed”
Response
{
"deliveries": [
{
"id": "wh_del_abc123",
"event": "meeting.scheduled",
"timestamp": "2025-01-20T10:35:00Z",
"status": "success",
"response_code": 200,
"attempts": 1,
"duration_ms": 145,
"url": "https://yourapp.com/webhooks/syncline"
},
{
"id": "wh_del_def456",
"event": "user.calendar_connected",
"timestamp": "2025-01-20T10:30:00Z",
"status": "failed",
"response_code": 500,
"attempts": 3,
"duration_ms": 5000,
"error": "Connection timeout after 3 attempts",
"url": "https://yourapp.com/webhooks/syncline"
}
],
"stats": {
"total_sent": 1247,
"success_rate": 0.987,
"avg_response_time_ms": 156,
"last_30_days": {
"success": 1231,
"failed": 16
}
},
"pagination": {
"next_cursor": "wh_del_xyz789",
"has_more": true
}
}
Response Fields
Array of webhook delivery records
Aggregate statistics about webhook health
Delivery Object
Unique delivery identifier
Event type (e.g., “meeting.scheduled”)
HTTP status code returned by your endpoint
Number of delivery attempts (max 3)
Response time in milliseconds
Error message if delivery failed
Use Cases
Debug Failed Deliveries
// Check recent failed webhooks
async function debugWebhookFailures() {
const response = await fetch(
'https://api.syncline.run/v1/platform/webhook/logs?status=failed&limit=20',
{
headers: { 'X-API-Key': process.env.SYNCLINE_API_KEY }
}
);
const { deliveries } = await response.json();
deliveries.forEach(delivery => {
console.log(`❌ Failed: ${delivery.event} at ${delivery.timestamp}`);
console.log(` Error: ${delivery.error}`);
console.log(` Attempts: ${delivery.attempts}`);
console.log(` Response Code: ${delivery.response_code}`);
});
}
Monitor Webhook Health
// Check webhook success rate
async function checkWebhookHealth() {
const { stats } = await fetch(
'https://api.syncline.run/v1/platform/webhook/logs',
{
headers: { 'X-API-Key': process.env.SYNCLINE_API_KEY }
}
).then(r => r.json());
if (stats.success_rate < 0.95) {
await alertTeam({
title: '⚠️ Webhook Health Alert',
message: `Webhook success rate is ${(stats.success_rate * 100).toFixed(1)}%`,
stats: stats.last_30_days
});
}
return {
health: stats.success_rate > 0.95 ? 'healthy' : 'degraded',
success_rate: stats.success_rate,
avg_response_time: stats.avg_response_time_ms,
recent_failures: stats.last_30_days.failed
};
}
Track Specific Events
// Monitor meeting scheduling webhooks
async function trackMeetingWebhooks() {
const response = await fetch(
'https://api.syncline.run/v1/platform/webhook/logs?event=meeting.scheduled&limit=100',
{
headers: { 'X-API-Key': process.env.SYNCLINE_API_KEY }
}
);
const { deliveries } = await response.json();
const analysis = {
total: deliveries.length,
successful: deliveries.filter(d => d.status === 'success').length,
avg_response_time: deliveries.reduce((sum, d) => sum + d.duration_ms, 0) / deliveries.length,
slow_deliveries: deliveries.filter(d => d.duration_ms > 1000).length
};
console.log('Meeting webhook analysis:', analysis);
return analysis;
}
// Set up automated monitoring
async function monitorWebhookPerformance() {
const { stats, deliveries } = await getWebhookLogs();
// Alert on high failure rate
if (stats.success_rate < 0.90) {
await sendAlert({
severity: 'high',
message: `Webhook failure rate: ${((1 - stats.success_rate) * 100).toFixed(1)}%`,
failed_count: stats.last_30_days.failed
});
}
// Alert on slow response times
if (stats.avg_response_time_ms > 2000) {
await sendAlert({
severity: 'medium',
message: `Webhook response time: ${stats.avg_response_time_ms}ms (above 2s threshold)`
});
}
// Alert on recent failures
const recentFailures = deliveries
.filter(d => d.status === 'failed')
.filter(d => Date.now() - new Date(d.timestamp).getTime() < 3600000); // Last hour
if (recentFailures.length > 5) {
await sendAlert({
severity: 'high',
message: `${recentFailures.length} webhook failures in the last hour`,
failures: recentFailures.map(f => ({
event: f.event,
error: f.error,
timestamp: f.timestamp
}))
});
}
}
// Run every 15 minutes
setInterval(monitorWebhookPerformance, 15 * 60 * 1000);
Common Failure Patterns
Connection Timeouts
{
"status": "failed",
"response_code": 0,
"error": "Connection timeout after 3 attempts",
"duration_ms": 30000
}
Solution: Check your webhook endpoint is responding within 30 seconds. Return 200 OK immediately and process asynchronously.
5xx Server Errors
{
"status": "failed",
"response_code": 500,
"error": "Internal server error",
"attempts": 3
}
Solution: Check your webhook handler logs. Common causes:
- Unhandled exceptions
- Database connection issues
- Missing environment variables
401 Unauthorized
{
"status": "failed",
"response_code": 401,
"error": "Invalid webhook signature",
"attempts": 3
}
Solution: Verify your webhook signature verification code. Ensure SYNCLINE_WEBHOOK_SECRET is set correctly.
SSL/TLS Errors
{
"status": "failed",
"response_code": 0,
"error": "SSL certificate verification failed",
"attempts": 3
}
Solution: Ensure your webhook URL uses a valid SSL certificate. Self-signed certificates are not supported.
Dashboard Example
// Build a webhook monitoring dashboard
async function buildWebhookDashboard() {
const { deliveries, stats } = await getWebhookLogs();
return {
overview: {
total_sent: stats.total_sent,
success_rate: (stats.success_rate * 100).toFixed(1) + '%',
avg_response_time: stats.avg_response_time_ms + 'ms',
health: stats.success_rate > 0.95 ? '🟢 Healthy' : '🟡 Degraded'
},
last_30_days: {
successful: stats.last_30_days.success,
failed: stats.last_30_days.failed,
failure_rate: (stats.last_30_days.failed / (stats.last_30_days.success + stats.last_30_days.failed) * 100).toFixed(1) + '%'
},
recent_deliveries: deliveries.slice(0, 10).map(d => ({
event: d.event,
status: d.status === 'success' ? '✓' : '✗',
response_time: d.duration_ms + 'ms',
timestamp: new Date(d.timestamp).toLocaleString()
})),
by_event_type: groupByEventType(deliveries)
};
}
function groupByEventType(deliveries) {
const grouped = {};
deliveries.forEach(d => {
if (!grouped[d.event]) {
grouped[d.event] = { total: 0, success: 0, failed: 0 };
}
grouped[d.event].total++;
if (d.status === 'success') {
grouped[d.event].success++;
} else {
grouped[d.event].failed++;
}
});
return grouped;
}
Best Practices
Regular Monitoring
Check webhook logs daily to catch issues early:
// Daily health check
async function dailyWebhookHealthCheck() {
const { stats } = await getWebhookLogs();
const report = {
date: new Date().toISOString().split('T')[0],
success_rate: stats.success_rate,
total_sent: stats.total_sent,
avg_response_time: stats.avg_response_time_ms,
recent_failures: stats.last_30_days.failed
};
// Store in database for trending
await db.webhook_health.create(report);
// Alert if degraded
if (stats.success_rate < 0.95) {
await notifyTeam(report);
}
}
Set Up Alerts
Configure alerts for critical issues:
- Success rate drops below 95%
- Average response time exceeds 2 seconds
- More than 5 failures in 1 hour
- Any SSL/TLS certificate errors
Investigate Patterns
Look for patterns in failed deliveries:
async function analyzeFai lurePatterns() {
const { deliveries } = await fetch(
'https://api.syncline.run/v1/platform/webhook/logs?status=failed&limit=200',
{ headers: { 'X-API-Key': process.env.SYNCLINE_API_KEY } }
).then(r => r.json());
// Group by error message
const errorTypes = {};
deliveries.forEach(d => {
const errorKey = d.error.split(':')[0]; // First part of error message
errorTypes[errorKey] = (errorTypes[errorKey] || 0) + 1;
});
// Most common failures
const sorted = Object.entries(errorTypes)
.sort(([,a], [,b]) => b - a);
console.log('Most common webhook failures:');
sorted.forEach(([error, count]) => {
console.log(` ${error}: ${count} occurrences`);
});
}