Skip to main content

Webhook Retry Policy

When a webhook delivery fails, Kallglot automatically retries the request with exponential backoff.

What Triggers a Retry

A webhook delivery is considered failed if:
  • Your endpoint returns a non-2xx HTTP status code
  • Your endpoint doesn’t respond within 30 seconds
  • The connection cannot be established
  • SSL/TLS handshake fails

Retry Schedule

Kallglot uses exponential backoff with jitter:
AttemptDelayTotal Time Elapsed
1Immediate0
2~1 minute1 minute
3~5 minutes6 minutes
4~30 minutes36 minutes
5~2 hours2.5 hours
6~5 hours7.5 hours
7~10 hours17.5 hours
8~24 hours41.5 hours
After 8 failed attempts (~41 hours), the webhook is marked as permanently failed.

Retry Headers

Retry attempts include additional headers:
HeaderDescription
Kallglot-Webhook-IdUnique ID for this delivery
Kallglot-Retry-CountCurrent retry attempt (0 for first attempt)
Kallglot-Original-TimestampWhen the event was first created
POST /webhooks/kallglot HTTP/1.1
Host: your-app.com
Content-Type: application/json
Kallglot-Signature: t=1711454400,v1=abc123...
Kallglot-Webhook-Id: wh_del_01HXYZ
Kallglot-Retry-Count: 2
Kallglot-Original-Timestamp: 1711454000

Idempotency

Because webhooks may be delivered multiple times, your handler must be idempotent. Use the id field to deduplicate:
async function handleWebhook(event) {
  // Check if already processed
  const processed = await db.webhookEvents.findOne({ eventId: event.id });
  if (processed) {
    console.log(`Event ${event.id} already processed, skipping`);
    return;
  }

  // Process the event
  await processEvent(event);

  // Mark as processed
  await db.webhookEvents.insert({
    eventId: event.id,
    processedAt: new Date()
  });
}

Monitoring Deliveries

Developer Portal

View delivery status in the Developer Portal:
  1. Go to Webhooks > select your endpoint
  2. Click Delivery History
  3. View status, response, and retry history for each event

Delivery Statuses

StatusDescription
pendingWaiting to be sent
deliveredSuccessfully delivered (2xx response)
retryingFailed, retry scheduled
failedAll retries exhausted

Webhook Events

Subscribe to meta-events about your webhooks:
{
  "type": "webhook_endpoint.disabled",
  "data": {
    "endpoint_id": "wh_01ABC",
    "url": "https://your-app.com/webhooks",
    "reason": "too_many_failures",
    "failed_events": 100
  }
}

Automatic Disabling

Endpoints are automatically disabled after:
  • 100 consecutive failed deliveries, or
  • 7 days of continuous failures
When disabled, you’ll receive an email notification and a webhook_endpoint.disabled event (to other healthy endpoints). To re-enable:
  1. Fix the underlying issue
  2. Go to Developer Portal > Webhooks
  3. Select the disabled endpoint
  4. Click Re-enable

Best Practices

Acknowledge receipt immediately and process asynchronously:
app.post('/webhooks', (req, res) => {
  // Verify signature
  // ...

  // Queue for processing
  queue.add(req.body);

  // Return immediately
  res.status(200).send('OK');
});
For reliability, push webhooks to a queue (Redis, SQS, RabbitMQ):
app.post('/webhooks', async (req, res) => {
  await sqs.sendMessage({
    QueueUrl: WEBHOOK_QUEUE_URL,
    MessageBody: JSON.stringify(req.body),
    MessageDeduplicationId: req.body.id
  });

  res.status(200).send('OK');
});
Events may arrive out of order. Use timestamps to handle this:
async function handleSessionEvent(event) {
  const session = await db.sessions.findOne({ id: event.data.id });

  // Only process if this event is newer
  if (session && event.created_at <= session.lastEventAt) {
    console.log('Skipping stale event');
    return;
  }

  await processEvent(event);
}
Monitor for failed webhooks and alert your team:
// Check for failures periodically
const failedWebhooks = await listWebhookEndpoints({
  status: 'failing'
});

if (failedWebhooks.data.length > 0) {
  await pagerduty.alert({
    message: `${failedWebhooks.data.length} webhook endpoints failing`
  });
}

Manual Retry

You can manually retry failed events from the Developer Portal:
  1. Go to Webhooks > select endpoint > Delivery History
  2. Find the failed event
  3. Click Retry
Or via API:
curl -X POST https://api.kallglot.com/v1/webhook_deliveries/wh_del_01HXYZ/retry \
  -H "Authorization: Bearer sk_live_your_api_key"

Event Expiration

Events are retained for 30 days. After that:
  • Events cannot be viewed in the Developer Portal
  • Manual retries are no longer possible
  • The event data is permanently deleted