Provider reference / SendGrid

How SendGrid delivers webhooks

SendGrid signs with ECDSA P-256, not an HMAC, under an x-twilio-email header. The verified format and a Web Crypto verifier.

Delivery behaviour

Read from the vendor's own documentation, last checked 2026-08-06. Where the vendor states no number, this table carries none.

Response budgetnot published by the vendor
Retrynot published by the vendor
Gives upnot published by the vendor

Signature

Verified against a working verifier proven by a test suite, not read from documentation. Last verified 2026-08-20.

AlgorithmECDSA P-256
Signed payload{timestamp}{body}
Encodingbase64
Headerx-twilio-email-event-webhook-signature
Tolerancenone enforced

Verify it

The raw request body, byte for byte, before any JSON parsing. Every scheme on this page breaks the moment a framework re-serializes the payload.

// ECDSA P-256 over "{timestamp}{body}", signature and key both base64.
const b64 = (s) => Uint8Array.from(atob(s), (c) => c.charCodeAt(0));

const key = await crypto.subtle.importKey(
  "spki",
  b64(verificationKey), // Mail Settings → Signed Event Webhook
  { name: "ECDSA", namedCurve: "P-256" },
  false,
  ["verify"],
);
const ts = req.headers["x-twilio-email-event-webhook-timestamp"];
const valid = await crypto.subtle.verify(
  { name: "ECDSA", hash: "SHA-256" },
  key,
  b64(req.headers["x-twilio-email-event-webhook-signature"]),
  new TextEncoder().encode(ts + rawBody),
);

What bites

The headers say x-twilio-email because Twilio owns SendGrid; the scheme is SendGrid's own and shares nothing with Twilio's HMAC-SHA1. A verifier keyed on the header prefix alone picks the wrong algorithm.

Read more

AnyHook sits in front of endpoints that receive from SendGrid: it answers inside the budget above, retries on its own schedule when your server is down, and keeps every event replayable. Change one URL, keep your code.

How it works →