Verify the webhook signature before any processing: compute the expected signature from the raw request body bytes and your signing secret using the algorithm specified by the PSP (typically HMAC-SHA256); reject any request with a missing or non-matching signature with HTTP 400.
Respond with HTTP 200 (or 204) as fast as possible — within 5–10 seconds for most PSPs — before performing any database writes, downstream API calls, or business logic; use an async queue (job queue, message broker) to hand off processing.
Deduplicate by event ID: store each processed event ID in a database or cache with a TTL long enough to cover the PSP's retry window (24–72 hours); at the start of processing, check if the event ID has been seen and skip if so.
Implement idempotent handlers: every processing step (order fulfillment, email send, ledger entry) must be safe to run twice; use database upserts and unique constraints rather than blind inserts.
Set up a polling reconciliation job that runs on a schedule (e.g., every 15 minutes): query the PSP's list endpoint for recent events or payment statuses and compare against your local state to catch any webhooks that were never delivered.
Alert on dead-letter queue depth or reconciliation mismatches; a payment that is 'paid' in the PSP but 'pending' in your system for more than 30 minutes indicates a processing failure requiring investigation.
Known gotchas
Webhooks are delivered at-least-once by all major PSPs — receiving the same event twice is normal, not an error; handlers that are not idempotent will double-fulfill orders or double-charge ledgers on duplicate delivery.
Returning a non-200 status to a webhook (including 3xx redirects) causes the PSP to retry; if your verification step rejects a legitimate webhook incorrectly (e.g., due to a middleware that re-parses the body before your signature check), you will receive repeated retries that all fail.
A webhook-only architecture is fragile — PSPs can experience webhook delivery outages lasting hours; without a polling fallback, your system will have orders stuck in pending state during those outages.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp