How to Test SendGrid Webhooks
SendGrid sends Event Webhooks for email delivery events — delivered, opened, clicked, bounced, and spam reports.
Looking for the broader picture? See the 7 best webhook testing tools (2026), or if you're already on Webhook.site, the 60-second migration to HookRay.
SendGrid Official Webhook Docs1. SendGrid Webhook Events
SendGrid can send the following webhook events to your endpoint:
deliveredopenclickbouncedroppeddeferredspam_reportunsubscribegroup_unsubscribegroup_resubscribe2. Set Up a Test Endpoint with HookRay
Follow these steps to start receiving SendGrid webhooks for testing:
- Go to HookRay and click "Start Testing — Free" to get your unique webhook URL.
- Copy the URL (e.g.,
https://h.hookray.com/abc123). - In your SendGrid dashboard, navigate to the webhook settings and paste the HookRay URL as your endpoint.
- Select the events you want to receive (see list above).
- Trigger a test event — HookRay will show the incoming webhook in real-time.
3. Sample SendGrid Webhook Payload
Here's an example of what a SendGrid webhook payload looks like:
{
"email": "user@example.com",
"event": "delivered",
"sg_message_id": "abc123.filter0001.12345",
"timestamp": 1710000000,
"category": [
"marketing"
]
}4. How to Verify SendGrid Webhook Signatures
- Algorithm
- ECDSA (P-256, SHA-256)
- Header
X-Twilio-Email-Event-Webhook-Signature- Encoding
- base64
SendGrid signs `{X-Twilio-Email-Event-Webhook-Timestamp}{raw_request_body}` with an ECDSA private key. Verify with the public key from Settings → Mail Settings → Event Webhooks (must be enabled per-webhook).
Node.js (Express)
// npm i @sendgrid/eventwebhook
import { EventWebhook } from '@sendgrid/eventwebhook';
import express from 'express';
const ew = new EventWebhook();
const PUBLIC_KEY = process.env.SENDGRID_WEBHOOK_PUBLIC_KEY!;
const ecPublicKey = ew.convertPublicKeyToECDSA(PUBLIC_KEY);
const app = express();
app.post(
'/webhooks/sendgrid',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature =
(req.headers['x-twilio-email-event-webhook-signature'] as string | undefined) ?? '';
const timestamp =
(req.headers['x-twilio-email-event-webhook-timestamp'] as string | undefined) ?? '';
const isValid = ew.verifySignature(
ecPublicKey,
req.body, // raw Buffer
signature,
timestamp,
);
if (!isValid) return res.status(403).send('invalid signature');
const events = JSON.parse(req.body.toString('utf8')); // array of events
res.json({ ok: true, count: events.length });
},
);Python (FastAPI)
# pip install sendgrid
import os
from sendgrid.helpers.eventwebhook import EventWebhook, EventWebhookHeader
from fastapi import FastAPI, Request, HTTPException
ew = EventWebhook()
public_key = ew.convert_public_key_to_ecdsa(
os.environ['SENDGRID_WEBHOOK_PUBLIC_KEY']
)
app = FastAPI()
@app.post("/webhooks/sendgrid")
async def sendgrid_webhook(request: Request):
body = await request.body()
signature = request.headers.get(EventWebhookHeader.SIGNATURE.lower(), '')
timestamp = request.headers.get(EventWebhookHeader.TIMESTAMP.lower(), '')
if not ew.verify_signature(public_key, body.decode(), signature, timestamp):
raise HTTPException(status_code=403, detail='invalid signature')
return {'ok': True}Capture a real SendGrid webhook with HookRay first, then replay the captured request against your verifier locally — that way you can iterate on the verification code without re-triggering events in SendGrid. Read SendGrid's official signing docs for the canonical reference, or see the cross-service signature verification guide for Ruby and timing-safe comparison patterns.
5. How SendGrid Retries Failed Webhooks
- Max attempts
- Up to 24h of retries
- Total window
- 24 hours
- Backoff
- Exponential
- Retries on
- Non-2xx responses
- Stops on
- Any 2xx response within timeout
If your handler is going to see the same SendGrid event multiple times, you need idempotency by event ID and the right response codes — see the Webhook Retry Strategies guide for the full pattern (idempotency tables, dead-letter queues, replaying captured events for tests). Cross-reference with SendGrid's official retry docs before relying on these numbers in production.
6. Frequently Asked Questions
How do I test SendGrid webhooks without deploying?
Use HookRay to get an instant public webhook URL. Paste it into your SendGrid dashboard's webhook configuration, trigger an event, and watch the payload arrive in real time. No code, no ngrok, no deployment required. The free tier captures 100 requests per month and works on all SendGrid event types.
Why aren't my SendGrid webhooks arriving?
The four most common causes: (1) the endpoint URL isn't publicly accessible — SendGrid can't reach localhost; (2) the wrong events are subscribed in your SendGrid dashboard; (3) signature verification is rejecting the request before your handler runs; (4) SendGrid can't reach your server because of a firewall, expired SSL certificate, or wrong DNS. Use HookRay's URL to isolate which of these four is failing — if HookRay receives the webhook, the problem is in your handler. If HookRay doesn't, the problem is in SendGrid configuration.
Why am I getting 400 or 500 errors from my SendGrid webhook?
SendGrid reports the response status your endpoint returned. HookRay accepts any payload and returns 200 OK by default, so if you see 400/500 in your SendGrid dashboard while pointing at HookRay, the issue is in SendGrid's configuration (wrong event, malformed signing secret, etc.). If you point at your own endpoint and get 400/500, the issue is in your handler — capture the request with HookRay, replay it locally, and debug from the captured payload.
How do I verify SendGrid webhook signatures?
SendGrid signs each webhook request with a shared secret. Capture the raw headers and body using HookRay, then verify the signature in your application using SendGrid's SDK or a standard HMAC library. Once verification works against HookRay-captured data, you can safely deploy. SendGrid's docs (linked above) cover the exact signing algorithm.
Can I replay a captured SendGrid webhook?
Yes — HookRay's replay feature re-sends any captured webhook to a different endpoint with one click. This is the fastest way to fix a buggy handler: capture the payload once, fix your code, and replay until it works. No need to re-trigger the event in SendGrid.
7. Next Steps
- Use HookRay's webhook replay feature to re-send captured webhooks while building your handler
- Enable smart parsing (Pro plan) to see SendGrid-specific fields highlighted automatically
- Check the SendGrid webhook documentation for the complete event reference
Ready to test SendGrid webhooks?
Get a free webhook URL in 5 seconds. No signup required.
Start Testing SendGrid Webhooks — FreeFree PDF: Webhook Testing Cheat Sheet 2026
One-page reference for 50+ APIs — canonical events, signing methods, sample payloads. Print it, pin it, share it.
📄 Download the cheat sheet (PDF, 180KB)