Webhook Handling Patterns I Use in Production

Webhooks fail in interesting ways. I explain the handling patterns I rely on for retries, signatures, and idempotent updates.

Webhook Handling Patterns I Use in Production

The focus here is reliable webhook handling in production — not generic admin advice, but what I actually shipped. Webhooks fail in interesting ways. I explain the handling patterns I rely on for retries, signatures, and idempotent updates.

Verify Every Incoming Event

Webhooks fail in interesting ways. I explain the handling patterns I rely on for retries, signatures, and idempotent updates.

  • signature validation — applied directly to reliable webhook handling in production.
  • idempotent handlers — applied directly to reliable webhook handling in production.
  • retry logs — applied directly to reliable webhook handling in production.
  • queue-friendly design — applied directly to reliable webhook handling in production.

Putting It Together

When delivering Webhook Handling Patterns I Use in Production, the build stayed focused on signature validation, idempotent handlers, retry logs, and queue-friendly design. That restraint kept the release small enough to test properly before go-live.

Design for Duplicate Delivery

Representative code from the implementation — simplified for readability, but structurally what I deploy.

JSON API response envelope

<?php
function api_response(bool $ok, $data = null, array $errors = [], int $code = 200): void
{
    http_response_code($code);
    header('Content-Type: application/json; charset=utf-8');
    echo json_encode([
        'success' => $ok,
        'data'    => $data,
        'errors'  => $errors,
        'meta'    => ['timestamp' => gmdate('c'), 'request_id' => bin2hex(random_bytes(8))],
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

Idempotent payment callback handler

<?php
$payload = file_get_contents('php://input');
$eventId = json_decode($payload, true)['id'] ?? '';

$stmt = $db->prepare('SELECT id FROM webhook_events WHERE event_id = ? LIMIT 1');
$stmt->bind_param('s', $eventId);
$stmt->execute();
if ($stmt->get_result()->num_rows > 0) {
    api_response(true, ['status' => 'duplicate_ignored']);
}
// process once, then persist event_id

Where This Approach Paid Off

Shipping reliable webhook handling in production cleanly meant the next developer could extend it without untangling hidden coupling.

The part worth copying is the scope discipline: solve the stated problem fully before adding adjacent nice-to-haves.

Closing Thoughts

  1. Start with the exact problem statement for reliable webhook handling in production — one sentence, no buzzwords.
  2. Prioritise signature validation before polishing secondary UI details.
  3. Validate idempotent handlers under realistic data volume, not demo rows.