# Sendgrid Event Webhook :::info[Beta Feature] This input is currently in beta. If you run into any issues, please reach out to product@monad.com. ::: Receives Twilio SendGrid Event Webhook deliveries (processed, delivered, deferred, bounce, dropped, open, click, spam report and unsubscribe events) at a Monad-hosted endpoint, verifies each delivery's signature, and emits one record per event. Use this for live events; use [Sendgrid Email Activity](./twilio-sendgrid-email-activity) for message history. **Sync Type: Push (Webhook)** ## Overview SendGrid's [Event Webhook](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook) posts an event to a URL you choose each time something happens to an email: it is processed, delivered, deferred, bounced, dropped, opened or clicked, reported as spam, or the recipient unsubscribes. This input is a **webhook receiver**: SendGrid pushes events to a Monad-hosted endpoint rather than Monad polling an API. Every delivery must be signed with SendGrid's **Signed Event Webhook** feature. The input checks each delivery's signature against your webhook's public verification key and rejects anything unsigned or altered. Each event is emitted with **all of SendGrid's fields preserved**, so new SendGrid fields flow through automatically. :::info[Event Webhook or Email Activity?] | | Sendgrid Event Webhook | [Sendgrid Email Activity](./twilio-sendgrid-email-activity) | | --- | --- | --- | | Data | One record per **event** | One record per **message**, with its latest status | | Delivery | Pushed by SendGrid as events happen | Polled from the Email Activity API | | History | Events from setup onward | Past messages within SendGrid's retention | | SendGrid add-on | Not required | Requires the Email Activity history add-on | Use this input for live, per-event data. Use Email Activity when you need history from before the webhook was set up. ::: ## How It Works 1. SendGrid sends a POST to the input's ingest URL containing a JSON array of events. 2. The input verifies the delivery's **`X-Twilio-Email-Event-Webhook-Signature`** header: an ECDSA signature over the **`X-Twilio-Email-Event-Webhook-Timestamp`** header followed by the request body, checked with your webhook's verification key. Deliveries that are unsigned, signed with a different key, altered, signed more than 72 hours ago, or dated more than 5 minutes in the future are rejected with `401`. 3. Each event in the array becomes one record. SendGrid retries any delivery that doesn't receive a success response, at increasing intervals for up to 24 hours after the event occurred. ## Prerequisites Before configuring this input, you need: 1. **Access to SendGrid's Mail Settings**, to create an Event Webhook. 2. **A free Event Webhook slot.** SendGrid limits how many Event Webhooks an account can have enabled, depending on its plan. If you're at the limit, free one up before setup. 3. **Tracking turned on** for the engagement events you want. Per SendGrid's [event reference](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event), open events need **Open Tracking**, click events need **Click Tracking**, and unsubscribe and group subscription events need **Subscription Tracking** (**Settings** > **Tracking**). ## Setup SendGrid shows the verification key only after the webhook is saved, and the webhook needs your Monad ingest URL. So you create the input with a temporary key first, then replace it with the real one. ### Step 1: Create the input in Monad 1. Create a **Sendgrid Event Webhook** input. For **Verification Key**, enter any temporary value (for example `pending`); you'll replace it in Step 3. 2. Add the input to a pipeline. 3. Copy the **Pipeline ID** from the pipeline details page. Your ingest URL is: `https://.data.monad.com` :::note[Self-hosted deployments] A per-pipeline ingest host needs the `*.data.` wildcard in place: a DNS record plus a matching certificate SAN. Monad Cloud has this. A self-hosted deployment has it only if whoever installed Monad set it up, so check with them if you are not sure. See [Customer Helm Install](/guides/customer_helm_install) for the setup. Without it, send exactly the same request to your own Monad hostname, with the pipeline ID in the path: `https:///api/v2/http/send/` Authentication, request body, and responses are the same either way. ::: Until the real key is in place, the input rejects every delivery. SendGrid retries rejected deliveries for up to 24 hours, so events sent during setup arrive once the key is set. ### Step 2: Create a signed webhook in SendGrid 1. In SendGrid, go to **Settings** > **Mail Settings**, then under **Webhook Settings** click **Event Webhooks**. 2. Click **Create new webhook**. 3. Enter a **Friendly Name** (for example `Monad`), set **Post URL** to the ingest URL from Step 1, and choose the **Actions to be posted** (the event types you want). 4. Under **Security features**, turn on **Enable Signed Event Webhook**. 5. Click **Save**. 6. Open the webhook again (cog > **Edit**) and copy the **verification key** shown under Signature verification. ### Step 3: Add the key to Monad 1. Edit the input in Monad and replace the temporary **Verification Key** with the key from Step 2. 2. In SendGrid, click **Test Your Integration** on the webhook. SendGrid posts a signed array of example events, which should appear as records in the pipeline. ## Configuration ### Settings This input has no settings. ### Secrets | Secret | Type | Required | Description | | ------ | ---- | -------- | ----------- | | Verification Key | string | Yes | The webhook's Signed Event Webhook public key. In SendGrid: Settings -> Mail Settings -> Event Webhooks, edit the webhook, turn on Enable Signed Event Webhook, save, then reopen the webhook and copy the verification key. Every delivery must carry a valid signature. | ## Record Fields Each record is one SendGrid event, with **all of SendGrid's fields preserved**. Fields vary by event type; these are the ones to know: | Field | Description | | --- | --- | | `event` | The event type, such as `processed`, `delivered`, `deferred`, `bounce`, `dropped`, `open`, `click`, `spamreport`, `unsubscribe`, `group_unsubscribe` or `group_resubscribe`. | | `timestamp` | When the event occurred, as a UNIX timestamp in seconds. | | `sg_event_id` | Unique ID for the event. SendGrid recommends it for deduplication. | | `sg_message_id` | ID of the message the event belongs to. Absent on some asynchronous bounces. | | `email` | The recipient's address. | See SendGrid's [Event Webhook reference](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) for every field by event type. ## Sample Record ```json { "email": "hello@world.com", "event": "dropped", "reason": "Bounced Address", "sg_event_id": "ZHJvcC0xMDk5NDkxOS1MUnpYbF9OSFN0T0doUTRrb2ZTbV9BLTA", "sg_message_id": "LRzXl_NHStOGhQ4kofSm_A.filterdrecv-p3mdw1-756b745b58-kmzbl-18-5F5FC76C-9.0", "smtp-id": "", "timestamp": 1600112492 } ``` ## Limitations - **No backfill.** Only events that occur after the webhook is enabled are ingested. For earlier activity, use [Sendgrid Email Activity](./twilio-sendgrid-email-activity). - **Signed deliveries only.** Signature verification can't be turned off; unsigned deliveries are rejected. - **Possible duplicates.** SendGrid retries deliveries that don't get a success response, so an event can arrive more than once. Deduplicate on `sg_event_id` if you need exactly-once. - **24-hour retry window.** If the endpoint is unreachable for longer than SendGrid's 24-hour retry window, those events are lost. - **One webhook, one pipeline.** Each SendGrid webhook posts to one URL. To send events to several destinations, route them downstream in the pipeline. - **Webhook slots.** SendGrid limits how many Event Webhooks can be enabled at once, depending on your plan. ## Troubleshooting ### 1. Deliveries rejected (401 or 500) - **Key isn't valid (500)**: If **Verification Key** still holds the temporary value from setup, or the pasted key is incomplete, the input can't check signatures and rejects every delivery with a `500`. Paste the full key from the webhook's settings in SendGrid. - **Wrong or changed key**: The key in Monad must match the webhook's current verification key. Turning signature verification off and saving deletes the key pair, and turning it back on generates a new one, so paste the new key into Monad. - **Signing not enabled**: Confirm **Enable Signed Event Webhook** is on for this webhook. Unsigned deliveries are always rejected. - **Wrong webhook**: If you have several Event Webhooks, each has its own key. Copy the key from the webhook whose **Post URL** is this input's ingest URL. ### 2. No data - **Webhook disabled or wrong URL**: Confirm the webhook is enabled and its **Post URL** is this input's ingest URL. **Test Your Integration** sends example events you can look for in the pipeline. - **Event types not selected**: Only the **Actions to be posted** you selected are sent. - **Tracking off**: Open, click and subscription events are only sent when **Open Tracking**, **Click Tracking** and **Subscription Tracking** are on in **Settings** > **Tracking**. ### 3. Missing historical events - Expected: there is no backfill. Use [Sendgrid Email Activity](./twilio-sendgrid-email-activity) for earlier messages. ## Related Articles - [Getting started with the Event Webhook](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook) - [Event Webhook reference](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/event) - [Event Webhook security features](https://www.twilio.com/docs/sendgrid/for-developers/tracking-events/getting-started-event-webhook-security-features) ## Sync frequency This is a push (receiver) input: Monad ingests records as the source sends them, so there is no polling interval. See [Input Sync Frequency](/docs/guides/sync-frequency) for details.