How do ESPs verify webhook and API integrity?
Still have a question, spotted an error, or have a better explanation or a source we should cite?
You've connected your ESP to your app via webhooks. Now a request arrives at your endpoint. How do you actually know it came from your ESP and not someone else?
That's the core problem webhook and API integrity verification solves. Your ESP (Email Service Provider) sends data to your server in real time, and without a way to verify the source, anyone could fake those requests. Here's how the protection actually works.
Webhook signature verification
Most ESPs sign every webhook payload using a shared secret and a hashing algorithm called HMAC-SHA256. When you set up a webhook, your ESP gives you a secret key. Only you and the ESP know it. When the ESP sends a payload to your endpoint, it runs the payload through HMAC-SHA256 using that secret and puts the resulting signature in a request header (something like X-Signature or X-Hub-Signature-256).
On your side, you do the exact same calculation using the raw request body and your stored secret. If your computed signature matches the one in the header, the payload is genuine and untampered. If it doesn't match, something's wrong. Reject it.
The key detail: you must compute the signature against the raw, unprocessed request body. If you parse the JSON first and then try to verify, the byte-for-byte comparison will fail even on a perfectly valid payload. (Ask anyone who's spent an afternoon debugging that one.)
Timestamp checks stop replay attacks
But a valid signature isn't enough on its own. An attacker could capture a legitimate webhook request and resend it later. That's called a replay attack, and it's why most ESPs include a timestamp in the payload or headers.
Your endpoint should check that the timestamp is recent, usually within five minutes of now. If a request arrives with a timestamp from two hours ago, reject it regardless of whether the signature checks out. It's a stale replay.
IP allowlisting as a backup layer
Now some ESPs publish a fixed range of IP addresses for their webhook servers. If yours does, you can configure your endpoint to accept requests only from those IPs. It's not a substitute for signature verification (IPs can change), but it adds a useful second layer. Check your ESP's documentation to see if they maintain a published IP range for this purpose.
API security follows a different pattern
Webhooks are inbound to your server. API calls are outbound from your code to the ESP. The integrity model flips accordingly.
API calls use authentication credentials you generate: API keys, OAuth tokens, or similar. You pass these with every request, and the ESP verifies them on their end. Your job here is to protect those credentials. Store them in environment variables, not in source code. Rotate them if you suspect they've been exposed. Scope them to the minimum permissions needed.
Good ESPs also enforce rate limiting (so a bug or bad actor can't flood their API) and require TLS on all endpoints, which means your credentials and data travel encrypted. Postmark, Twilio SendGrid, and Mailgun all document their webhook signature formats clearly, which makes implementation straightforward.
Your checklist for a secure webhook integration
- Store your webhook secret securely (environment variable, secrets manager)
- Verify the signature on every inbound request before processing it
- Compute the signature against the raw body, not the parsed payload
- Check the timestamp and reject anything older than five minutes
- Return a
200 OKquickly, then process asynchronously (slow responses can cause the ESP to retry, which creates duplicates) - Log failed verification attempts so you can spot patterns
- Rotate your webhook secret if you ever suspect it's been exposed
If you want to audit your broader ESP security setup, that's a natural next step once your webhook verification is solid. And if something's actively broken right now, our SOS hotline is free to use. No pitch, just help.
Contributors
Who worked on this answer
Every name links to their profile. Every company links to their site. Real people, real accountability.