SendGrid Event Webhook Configuration
SendGrid Event Webhook Configuration
The SendGrid Event Webhook integration enables real-time tracking of email delivery events including opens, clicks, bounces, spam reports, and more. This integration automatically updates email message statuses and triggers internal webhooks when key events occur.
Overview
What is SendGrid Event Webhook?
SendGrid Event Webhook is a service that sends HTTP POST notifications to your API when email events occur. This allows you to:
- Track delivery status in real-time
- Monitor email engagement (opens, clicks)
- Handle bounces and delivery failures
- Detect spam reports and unsubscribes
- Maintain accurate email status records
Supported Events
The following SendGrid events are supported and will update email message statuses:
| Event | Email Status | Triggers Internal Webhook | Description |
|---|---|---|---|
processed | sent | No | Email has been processed and sent to SendGrid’s delivery queue (optional) |
delivered | delivered | Yes | Email was successfully delivered to the recipient’s mail server |
open | opened | Yes | Recipient opened the email |
click | clicked | Yes | Recipient clicked a link in the email |
bounce | bounced | Yes | Email bounced (hard or soft bounce) |
dropped | dropped | No | Email was dropped and not sent (invalid address, spam, etc.) |
deferred | deferred | No | Delivery was temporarily delayed |
spamreport | spam_report | No | Recipient marked email as spam |
unsubscribe | unsubscribe | No | Recipient unsubscribed from emails |
Note: The processed event is optional and provides early notification that an email entered the sending queue. While it updates the status to sent, it does not trigger internal webhooks since it doesn’t represent final delivery or engagement.
Configuration
Webhook Endpoint URL
The SendGrid Event Webhook endpoint is:
https://your-domain.com/api/sendgrid-inbound-parse-RaUDu49Mbkh2W7WrhU7XngdB3xEa3amDImportant Security Notes:
- The path includes a security token (
RaUDu49Mbkh2W7WrhU7XngdB3xEa3amD) that must not be changed - The endpoint uses both Basic Authentication and signature verification for security
- Always use HTTPS - never HTTP
Step-by-Step Configuration in SendGrid
Follow these steps to configure the Event Webhook in your SendGrid account:
-
Navigate to Event Webhook Settings
- Log into your SendGrid account at https://app.sendgrid.com
- Go to Settings → Mail Settings → Event Webhook
-
Enter the Webhook URL
- In the “HTTP POST URL” field, enter your webhook endpoint:
https://your-domain.com/api/sendgrid-inbound-parse-RaUDu49Mbkh2W7WrhU7XngdB3xEa3amD
- Replace
your-domain.comwith your actual domain (e.g.,api.dev.pulsecrm.com)
- In the “HTTP POST URL” field, enter your webhook endpoint:
-
Enable HTTPS POST
- Ensure “Enable HTTPS” is turned ON
- This is required for secure transmission of event data
-
Select Events to Track
- Enable the following required events by checking their boxes:
- ✓ Delivered
- ✓ Opened
- ✓ Clicked
- ✓ Bounced
- ✓ Dropped
- ✓ Deferred
- ✓ Spam Report
- ✓ Unsubscribe
- Optionally enable:
- Processed (for early queue entry notification)
- Enable the following required events by checking their boxes:
-
Enable Signature Verification
- Ensure “Signature Verification” is turned ON
- This is automatically handled by the endpoint - no additional configuration needed
-
Save Configuration
- Click “Save” to activate the webhook
- SendGrid will begin sending events to your endpoint immediately
Test the Configuration
After saving, SendGrid provides a “Test Your Integration” button that sends a sample event to verify the endpoint is working correctly.
Verification
Send a Test Email
To verify the integration is working properly, send a test email using the sendEmail function:
import { sendEmail } from "lib/sendgrid.ts";import type { EmailEntityInfo } from "lib/sendgrid.ts";
// Prepare entity info to track this emailconst entityInfo: EmailEntityInfo = { accountName: "Test Account", accountId: "account-123", entityType: "lead", // or "application", "merchant", "ticket" entityId: "lead-456",};
// Send test emailawait sendEmail( { to: "recipient@example.com", subject: "Test Email for Event Tracking", text: "This is a test email to verify SendGrid Event Webhook integration.", html: "<p>This is a test email to verify SendGrid Event Webhook integration.</p>", }, "PulseCRM", entityInfo);Verify Email Message Records
After sending the test email, verify that records are created and updated:
-
Check
emailMessagesTable- A new record should be created with the
messageIdfrom SendGrid - Initial status will be
triggered - The
entityType,entityId, andaccountIdshould match yourentityInfo
- A new record should be created with the
-
Check
emailMessageEventsTable- As events arrive from SendGrid, new event records are created
- Each event includes the
eventtype,timestamp, and relevant metadata - Multiple events for the same email will create multiple event records
-
Monitor Status Updates
- The
emailMessages.statusfield updates automatically as higher-priority events arrive:triggered→sent(if processed event enabled)sent→delivered(when delivered)delivered→opened(when recipient opens)opened→clicked(when recipient clicks a link)
- Negative events (
bounced,dropped,spam_report,unsubscribe) have the highest priority and will override positive statuses
- The
Verify Internal Webhooks
For events that trigger internal webhooks (delivered, open, click, bounce), the webhook processing happens via:
await triggerWebhooks(pulseEvent, accountId, webhookPayload, false);The webhook payload includes:
messageId- SendGrid message IDaccountId- Account the email belongs toentityType- Entity type (lead, application, etc.)entityId- Entity IDevent- SendGrid event nametimestamp- When the event occurredstatus- Current email status after processing the event- Additional metadata (IP, user agent, URL clicked, bounce reason, etc.)
Technical Implementation Reference
Webhook Endpoint
The webhook endpoint implementation is located at:
api/sendgrid-inbound-parse-RaUDu49Mbkh2W7WrhU7XngdB3xEa3amD/route.tsKey features:
- Basic Authentication: Validates the
Authorizationheader - Signature Verification: Verifies SendGrid’s ECDSA signature using the public key
- Event Processing: Routes events to
processSendgridWebhookEventsfor storage and webhook triggering - Dual Purpose: Handles both Event Webhook (JSON) and Inbound Parse (FormData) requests
Event Processing Service
Event processing logic is located at:
lib/services/email-messages.service.tsKey functions:
processSendgridWebhookEvents(events)- Processes an array of eventsprocessSendgridWebhookEvent(event)- Processes a single event with deduplication- Status priority system ensures correct final status (e.g.,
clickedoverridesopened) - Duplicate event detection prevents multiple webhook triggers for the same event
Event Status Priority
Email statuses follow a priority system to ensure the most significant status is maintained:
| Priority | Status | Value |
|---|---|---|
| 10 (Highest) | bounced, dropped, spam_report, unsubscribe | Delivery failures |
| 5 | clicked | Highest engagement |
| 4 | opened | Medium engagement |
| 3 | delivered | Successful delivery |
| 2 | deferred | Temporary delay |
| 1 | sent | Processed for sending |
| 0 (Lowest) | triggered | Initial state |
Once a higher-priority status is set, lower-priority events will not downgrade it. For example, if an email is bounced, subsequent delivered events (if any) will not change the status.
Troubleshooting
Events Not Arriving
- Verify webhook is enabled in SendGrid Mail Settings
- Check the webhook URL is correct and includes the security token
- Ensure HTTPS is enabled (HTTP will not work)
- Verify signature verification is enabled in SendGrid
- Check server logs for rejected requests or authentication failures
Email Status Not Updating
- Verify the message ID exists in the
emailMessagestable - Check
emailMessageEventstable to see if events are being recorded - Review event priority - lower priority events don’t override higher ones
- Check for processing errors in application logs
Duplicate Events
- Duplicate events are automatically detected using the
sg_event_idfield - The database has a unique constraint preventing duplicate event records
- Internal webhooks are only triggered once per unique event
Internal Webhooks Not Triggering
- Verify the event type - only
delivered,open,click, andbouncetrigger internal webhooks - Check webhook configuration for the account
- Review webhook logs for delivery failures
- Ensure it’s a new event - duplicate events don’t trigger webhooks
Security Considerations
Authentication Methods
The webhook endpoint uses two layers of security:
-
Basic Authentication
- Simple authentication check on incoming requests
- Provides basic protection against unauthorized access
-
Signature Verification
- SendGrid signs each webhook request with an ECDSA signature
- The endpoint verifies signatures using SendGrid’s public key
- Prevents spoofed or tampered webhook requests
Best Practices
- Never expose the security token in the webhook URL
- Monitor failed authentication attempts in server logs
- Regularly review email event logs for anomalies
- Use environment-specific endpoints (dev, staging, production)
- Keep SendGrid API keys secure and rotate them periodically
Related Documentation
- SendGrid Official Event Webhook Documentation
- Tickets API - Using email tracking with support tickets
- Applications API - Tracking application-related emails
- Leads API - Managing lead communication
API Endpoints
Internal Endpoints (Automated)
POST /api/sendgrid-inbound-parse-RaUDu49Mbkh2W7WrhU7XngdB3xEa3amD- Webhook receiver (called by SendGrid)
Management Endpoints
- Email message tracking is automatic - no manual API calls required
- Query email messages and events through entity-specific endpoints (leads, applications, etc.)
Database Schema
Email Messages Table
{ id: number, messageId: string, // SendGrid message ID accountId: string, entityType: EmailEntityType, // "lead", "application", "merchant", "ticket" entityId: string, toEmail: string, fromEmail: string, subject: string, status: EmailStatus, // Current status based on events createdAt: Date, updatedAt: Date}Email Message Events Table
{ id: number, emailMessageId: number, // Foreign key to emailMessages sgEventId: string, // Unique SendGrid event ID (for deduplication) event: string, // Event type: "delivered", "open", etc. timestamp: Date, // When event occurred ip: string, // Recipient IP (if available) userAgent: string, // Recipient user agent url: string, // Clicked URL (for click events) reason: string, // Bounce/drop reason bounceType: string, // "hard" or "soft" rawPayload: JSON, // Full SendGrid event data createdAt: Date}Unique constraint on sgEventId prevents duplicate event records.