← Home ← Codex ← DEBT
Browse by Category
+ added · updated 7d
← Back to glossary

Webhook Design

API Design PHP 5.0+ Intermediate
debt(d7/e5/b5/t7)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). The detection_hints list semgrep and postman as tools, but missing HMAC validation and non-idempotent consumers are logic-level issues — semgrep can catch structural patterns like missing signature checks, but idempotency gaps and silent retry loops typically only surface during code review or integration/load testing in staging or production.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes three distinct practices: HMAC validation, async queue processing, and idempotency via event ID. This isn't a single-line patch — it requires introducing a queue consumer, storing processed event IDs, and adding signature verification middleware, touching multiple layers of the application.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Applies to web and api contexts broadly. Every webhook endpoint in the codebase must implement the same three patterns (signature validation, async processing, idempotency), and any developer adding a new webhook consumer must understand and follow these practices, creating an ongoing structural tax across relevant work streams.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states that developers believe webhooks are fire-and-forget, not realizing providers retry on failure and consumers must be idempotent. This contradicts the intuitive mental model of HTTP (one request, one response, move on). The consequence — duplicate payment charges, emails, or DB records — is severe, and the 'obvious' naive implementation (process inline on receipt) is wrong in at least three distinct ways simultaneously.

About DEBT scoring →

Also Known As

webhook HTTP callback event notification webhook security

TL;DR

Best practices for reliable webhooks — HMAC signature verification, idempotency, delivery retry with exponential backoff, and handling slow consumers with queues.

Explanation

Webhooks push events to consumer endpoints via HTTP POST. Design considerations: Signature verification (HMAC-SHA256 of the payload with a shared secret — prevents forged payloads), idempotency (the same event may be delivered multiple times — consumers must be idempotent), delivery guarantees (retry with exponential backoff on non-2xx responses), timeouts (consumer must respond within 5-30 seconds — queue slow processing), event ordering (not guaranteed — include timestamps and sequence numbers), and dead letter handling (failed deliveries after retries need alerting).

Common Misconception

Webhooks are fire-and-forget — providers retry on failure, so consumers must be idempotent; receiving the same event twice must produce the same result, not duplicate side effects.

Why It Matters

A webhook consumer that processes a payment event twice (due to retry) charges a customer twice — idempotency using the event ID prevents duplicate processing.

Common Mistakes

  • Not verifying HMAC signature — any HTTP client can forge webhook payloads.
  • Non-idempotent consumers — retries cause duplicate charges, emails, or database records.
  • Slow processing in webhook handler — slow handlers cause timeouts and trigger retries.
  • No dead letter handling — failed webhooks silently lost means missed events.

Code Examples

✗ Vulnerable
// No signature verification, not idempotent:
$payload = file_get_contents('php://input');
$event   = json_decode($payload);
// No verification — anyone can POST fake events!
if ($event->type === 'payment.completed') {
    $this->processPayment($event->data); // Not idempotent — retries = double charge!
}
✓ Fixed
// Secure webhook handler:
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? '';

// Verify HMAC signature:
$expected = 'sha256=' . hash_hmac('sha256', $payload, WEBHOOK_SECRET);
if (!hash_equals($expected, $signature)) {
    http_response_code(401); exit;
}

$event = json_decode($payload);

// Idempotency — skip if already processed:
if ($this->events->isProcessed($event->id)) {
    http_response_code(200); exit; // Acknowledge but skip
}

// Respond 200 immediately, process asynchronously:
http_response_code(200);
ProcessWebhookJob::dispatch($event->id)->afterResponse();
$this->events->markProcessed($event->id);

Added 16 Mar 2026
Edited 22 Mar 2026
Views 53
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 2 pings S 2 pings M 0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 1 ping M 0 pings T 0 pings W
No pings yet today
No pings yesterday
ChatGPT 13 Amazonbot 9 Perplexity 5 Google 5 Ahrefs 4 SEMrush 4 Scrapy 4 Claude 1 Meta AI 1 PetalBot 1
crawler 42 crawler_json 5
DEV INTEL Tools & Severity
🟠 High ⚙ Fix effort: Medium
⚡ Quick Fix
Validate webhook signatures (HMAC-SHA256), respond with 200 immediately and process asynchronously via queue, implement idempotency via event ID — these three practices prevent the common webhook failures
📦 Applies To
PHP 5.0+ web api
🔗 Prerequisites
🔍 Detection Hints
Webhook endpoint with no signature validation; processing webhook inline taking >5 seconds causing retries; no idempotency check for duplicate delivery
Auto-detectable: ✓ Yes semgrep postman
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Medium ✗ Manual fix Fix: Medium Context: File Tests: Update
CWE-345 CWE-20


✓ schema.org compliant