Prompt
I'm building an event-driven integration and need reliable inbound webhook handling
Latest observation
Oct 5, 2026
OpenAI APIWeb search: off
Reliable inbound webhook handling usually comes down to four things: authenticate, deduplicate, acknowledge fast, and process asynchronously.
Recommended flow
-
Receive webhook
- Validate the request signature or secret token immediately.
- Reject anything invalid with
401/403.
-
Acknowledge quickly
- Return a
2xxas soon as the event is safely persisted. - Avoid doing business logic inline if it might take more than a few hundred milliseconds.
- Return a
-
Persist the event first
- Store the raw payload, headers, timestamp, and provider event ID.
- This gives you an audit trail and a recovery path.
-
Deduplicate
- Use the provider’s event ID, or construct an idempotency key from stable fields.
- Enforce uniqueness at the database or queue level.
-
Process asynchronously
- Push the event into a queue or job worker.
- Your worker should be retryable and idempotent.
-
Handle retries safely
- Webhook providers often retry on timeout or non-2xx.
- Your endpoint should tolerate duplicates and out-of-order delivery.
Core design principles
1) Idempotency
Assume the same webhook may arrive multiple times.
Do:
- Keep a unique constraint on
provider_event_id - Make downstream writes idempotent
- Use upserts where possible
Don’t:
- Trust “at least once” delivery to mean “once”
2) Fast ACK
Webhook senders often expect a response within a short timeout.
Pattern:
- Verify
- Persist
- Enqueue
- Respond
200 OK
If processing is heavy, move it out of the request path.
3) Signature verification
Use the provider’s recommended verification method:
- HMAC signature with shared secret
- Public-key verification
- Timestamp tolerance to prevent replay attacks
Check for:
- Body tampering
- Wrong secret
- Expired timestamps
4) Replay protection
Store the event ID and a received-at timestamp. Reject:
- duplicates
- stale payloads outside your allowed window
- invalid signatures
5) Observability
Add:
- request ID / event ID logging
- metrics for success, duplicate, invalid signature, processing failure
- dead-letter queue for poison messages
Minimal architecture
Webhook endpoint
- Authenticates
- Saves event
- Emits job
Queue/worker
- Processes business logic
- Retries on transient failure
- Sends to dead-letter after max attempts
Database
- Stores raw webhook events
- Stores processed state / side effects
Example pseudocode
def webhook_handler(request):
body = request.raw_body
sig = request.headers.get("X-Signature")
if not verify_signature(body, sig, secret):
return 403
event = parse_json(body)
event_id = event["id"]
try:
save_raw_event_once(event_id, body, request.headers)
except DuplicateEvent:
return 200
queue.publish("process_webhook", {"event_id": event_id})
return 200
Worker:
def process_webhook(job):
event = load_raw_event(job["event_id"])
if event_already_processed(event.id):
return
apply_business_logic(event)
mark_processed(event.id)
Common pitfalls
- Doing side effects before persistence
- Not verifying signatures
- Returning
200before the event is safely stored - Assuming delivery order
- Not designing for duplicate delivery
- Missing dead-letter handling
- Logging secrets or full sensitive payloads
Practical checklist
- Verify request authenticity
- Store raw event payload
- Deduplicate by event ID
- Return
2xxquickly - Process asynchronously
- Make processing idempotent
- Retry transient failures
- Add dead-letter handling
- Monitor duplicates/failures
- Keep an audit trail
If you want, I can also give you:
- a reference architecture for AWS/GCP/Azure,
- a database schema for webhook event storage, or
- an implementation example in Node.js, Python, or Go.