Skip to content
← Automation & Integrations

Draft — in editorial review, not yet published. Content has not been approved by a human reviewer.

Lesson 16 / 50 · Version 2.2.0

Webhooks from First Principles

Level
Beginner–Intermediate
Duration
15 min learn + 15 min apply
Prerequisites:
Lessons 11 and 15

Why it matters: Webhooks power instant integrations, but an open endpoint will accept anything unless you verify it. Retries and duplicate deliveries are normal, so receivers must be built for them.

By the end you can:

  • Explain webhook vs. polling
  • Verify a signed request
  • Deduplicate and acknowledge safely
  • Handle out-of-order events

Learn (15 min)

1. Event notifications (5 min)

A webhook is an HTTP request the provider sends to your URL when an event occurs.

POST /hooks/booking
Content-Type: application/json
X-Signature: t=1730039000,v1=5257a869...

{ "id": "evt_91", "type": "booking.created",
  "data": { "email": "jane@firm.com", "start": "2026-11-03T15:00:00Z" } }

Schemas and header names are provider-specific. Follow the provider's documentation.

2. Verify before trusting (5 min)

Anyone can POST to your URL. Use the provider's documented signature scheme. Typical pattern: compute an HMAC of the raw body (often with a timestamp) using a shared signing secret, then compare in constant time.

import hmac, hashlib
def valid(raw_body: bytes, header_sig: str, secret: bytes) -> bool:
    expected = hmac.new(secret, raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header_sig)

(Exact signing string differs by provider. Don't re-serialize the JSON before hashing.) Also check event type, required fields, HTTPS, and timestamp freshness if offered. Never log full sensitive payloads.

3. Acknowledge fast, process safely (5 min)

Providers retry if you're slow or return an error. Pattern: verify → check event.id against a store → save it → reply 2xx quickly → process in the background. Duplicates are skipped; late or out-of-order events are reconciled against current state (query the source) rather than trusting arrival order.

Apply (15 min)

Worked example (3 min).

receive → verify signature → validate type/fields
       → if event.id seen: return 200, do nothing
       → store event.id → enqueue job → return 200
job: update CRM (upsert by booking id) → on failure retry, then alert

If the same booking.created arrives twice, the second hits the "seen" check and nothing repeats.

Lab (7 min): Break your receiver on paper.

  1. For the example flow, write what happens in each case: invalid signature, duplicate event, event arriving after its canceled event, slow database (response > provider timeout), malformed JSON.
  2. For each, state the response code and side effect.

Deliverable: A five-row failure-handling table. You're done when: No row causes a duplicate or lost side effect.

Check yourself (5 min)

  1. Webhook vs. polling?
  2. Why verify a signature?
  3. Scenario: The provider retries every minute because your endpoint takes 40 seconds. What do you change?
  4. What prevents duplicate side effects?
  5. Events arrive out of order. What do you do?

Reference

Common mistakes

SymptomLikely causeFix
Fake events acceptedNo signature checkVerify with the signing secret
Signature never matchesHashed re-serialized JSONHash the raw bytes
Duplicate CRM entriesNo event-ID dedupeStore processed event IDs

Cheat sheet: Verify → validate → deduplicate → acknowledge → process → monitor.

Key terms: webhook, endpoint, signature, event ID, idempotency, retry.

Interview prompts: How would you secure a public webhook endpoint? How do you handle event ordering?

Go deeper: Stripe webhooks · HTTP semantics, RFC 9110 · n8n Webhook node

Next: Lesson 17 — OAuth, how apps get permission.