Home/Email API/Secure webhooks

How to secure webhooks

A webhook endpoint is a public URL that mutates your system. Unverified, it's an open door: anyone who finds it can POST fake events. Signature first, everything else second.

Verified By Kam Low, Co-founder · Updated August 19, 2026

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.

Verified is not the same as safe
Layer 1 · everyone does this
HMAC signature verifiedproves who sent it
Layer 2 · the one skipped
replay defencetimestamp window or seen-ID store
And on your sideidempotency key, header or body
Why layer 1 is not enougha captured request replays with a valid signature
A valid signature only proves origin. Replay defence is the layer that stops the same request landing twice.

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.

Incoming webhook
{ "event": "delivered" … }
X-Nitrosend-Signature:
sha256=7f3a…c91e
Your server verifies
hmac_sha256(secret, body)
== header signature?
match → process ✓ no match → drop
Anyone can POST to a public URL. Only Nitrosend can sign with your secret. Same figure, second crop, works for /webhook-test.

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.

First send in thirty seconds.

Simple pricing. Unlimited contacts.

Every plan includes full stack emailing: Flows, Newsletter Campaigns and Transactional Email, plus our NitroWheel LLM and all agent integrations (Claude, ChatGPT, Codex, Cursor and others). Pay for what you send, not who you store.

Plan limits are ceilings, not guaranteed immediate send headroom; only mature, clean volume sent through that exact sender can raise its capacity.

Free
$0
forever
  • Emails 8,000then 500/mo
  • Email types Transactional & Marketing
  • AI actions 20/mo
  • Contacts Free & Unlimited
  • Brands 3
  • Seats 1
  • Commercial recipients / rolling 24h 100
  • Email validation Prepaid only
Start free
Ultra
$100
per month
  • Emails 125,000/month
  • AI actions 5,000/mo
  • Brands 10
  • Seats 10 · Domains 10
  • Frontier AI Included
  • Dedicated IP Available
  • Commercial recipients / rolling 24h 62,500
  • Email validation Prepaid only
Get started
Enterprise
$300
per month
  • AI actions Unlimited
  • Unlimited brands & domains Included
  • SSO / SAML Included
  • 99.9% SLA Included
  • Commercial recipients / rolling 24h Contracted
  • Email validation Prepaid only
Get started

Free forever. No credit card required. See full comparison →