The threat is simpler than you think
Your webhook URL will leak: logs, browser history, a screenshot. The attack isn't exotic, it's curl: a forged "bounced" event that suppresses your best customer, or a fake "delivered" that corrupts your analytics. Any endpoint that acts on unverified POSTs hands write access to strangers.
The four controls
1. Verify the signature. Every Nitrosend event carries an HMAC-SHA256 signature computed over the payload with your webhook secret. Recompute, compare with a constant-time check, reject mismatches before parsing anything.
2. Bound the timestamp. Reject events older than a few minutes; that turns a captured payload into a dead one and kills replay attacks.
3. Process idempotently. Key on the event ID so a replayed or retried event changes nothing the second time.
4. Keep the secret a secret. Environment, not code; rotate it if it ever touches a log.
We practice number three on the write side too. Our send path accepts an idempotency key either as an Idempotency-Key header or as idempotency_key in the request body, so a replayed request lands on the original send instead of creating a second one. And our contact endpoints return the same 201 response for new and existing contacts, which keeps duplicate-email probing from enumerating who is in an audience.
The same discipline applies when you're the one receiving a platform's webhooks. Our Shopify app runs an HMAC-verified install handler, returns exactly the status codes Shopify expects so it never gets silently deactivated, and implements all three mandatory GDPR webhooks. Receiving has an invariant of its own: we mirror provider open webhooks into a single counter, email:open_total, so the number stays true across both writers. And a lesson from the abuse side of the fence: when you suspend anything, the block has to cover every send path. We once silenced an account and watched mail keep flowing through a path the block didn't reach, which is why a single gate now fronts them all. A control that covers most paths covers none. And the synchronous edge of that gate is narrow on purpose: phishing that sends from your own lookalike domain still passes it, with comprehensive recall handled by a separate AI content-risk review layer.
The pipe itself is held to the same standard. TCP 2525 is firewall-restricted to our API host, TLS and exact SMTP authentication are mandatory, and every one-recipient route snapshot is HMAC-signed, with unsigned, replayed, or multi-hop requests rejected. The signature discipline we ask of your endpoint is the one our own infrastructure runs on.
Full parameters and responses live in the REST API docs and the API reference.
Go deeper
Prove the controls work before production: test your webhook, including the wrong-signature and replay cases. Signing the receipt is the same instinct as SPF, DKIM and DMARC authentication on the outbound side, and it matters most for transactional email.