> ## Documentation Index
> Fetch the complete documentation index at: https://docs.transmit.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks

> Track email delivery events in real-time

## What are Webhooks?

Webhooks allow you to receive real-time notifications when events occur in your Transmit account. Subscribe to specific event types and receive HTTP POST requests to your endpoint whenever those events happen.

## Available Event Types

### Email Events

<AccordionGroup>
  <Accordion title="email.sent" defaultOpen>
    Triggered when an email has been successfully submitted to the email provider for delivery.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_email123_sent",
      "type": "email.sent",
      "created_at": 1704894225000,
      "data": {
        "email_id": "email_abc123",
        "from": "hello@example.com",
        "to": ["user@example.com"],
        "subject": "Welcome to Transmit",
        "sent_at": 1704894225000
      }
    }
    ```
  </Accordion>

  <Accordion title="email.delivered">
    Triggered when an email has been successfully delivered to the recipient's mail server.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_email123_delivered",
      "type": "email.delivered",
      "created_at": 1704894230000,
      "data": {
        "email_id": "email_abc123",
        "from": "hello@example.com",
        "to": ["user@example.com"],
        "subject": "Welcome to Transmit",
        "delivered_at": 1704894230000,
        "provider": "aws_ses",
        "provider_message_id": "0000014a-f4d4-4f4f-8f4f-4f4f4f4f4f4f"
      }
    }
    ```
  </Accordion>

  <Accordion title="email.opened">
    Triggered when a recipient opens an email (tracking pixels enabled).

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_email123_opened",
      "type": "email.opened",
      "created_at": 1704894245000,
      "data": {
        "email_id": "email_abc123",
        "to": "user@example.com",
        "opened_at": 1704894245000,
        "user_agent": "Mozilla/5.0...",
        "ip_address": "192.0.2.1"
      }
    }
    ```
  </Accordion>

  <Accordion title="email.clicked">
    Triggered when a recipient clicks a link in an email (link tracking enabled).

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_email123_clicked",
      "type": "email.clicked",
      "created_at": 1704894250000,
      "data": {
        "email_id": "email_abc123",
        "to": "user@example.com",
        "clicked_at": 1704894250000,
        "link": "https://example.com/welcome",
        "user_agent": "Mozilla/5.0...",
        "ip_address": "192.0.2.1"
      }
    }
    ```
  </Accordion>

  <Accordion title="email.bounced">
    Triggered when an email bounces (hard or soft bounce).

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_email123_bounced",
      "type": "email.bounced",
      "created_at": 1704894260000,
      "data": {
        "email_id": "email_abc123",
        "to": "invalid@example.com",
        "bounced_at": 1704894260000,
        "bounce_type": "hard",
        "bounce_reason": "mailbox_full",
        "diagnostic_code": "550 5.1.1 User unknown"
      }
    }
    ```
  </Accordion>

  <Accordion title="email.complained">
    Triggered when a recipient marks an email as spam.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_email123_complained",
      "type": "email.complained",
      "created_at": 1704894270000,
      "data": {
        "email_id": "email_abc123",
        "to": "user@example.com",
        "complained_at": 1704894270000,
        "feedback_type": "abuse"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Domain Events

<AccordionGroup>
  <Accordion title="domain.added">
    Triggered when a new domain is added to your account.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_domain123_added",
      "type": "domain.added",
      "created_at": 1704894280000,
      "data": {
        "domain_id": "domain_abc123",
        "domain": "example.com",
        "apex_domain": "example.com",
        "nickname": "Production Domain",
        "status": "pending"
      }
    }
    ```
  </Accordion>

  <Accordion title="domain.verified">
    Triggered when a domain has been successfully verified.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_domain123_verified",
      "type": "domain.verified",
      "created_at": 1704894290000,
      "data": {
        "domain_id": "domain_abc123",
        "domain": "example.com",
        "verified_at": 1704894290000
      }
    }
    ```
  </Accordion>

  <Accordion title="domain.failed_verification">
    Triggered when domain verification fails.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_domain123_failed",
      "type": "domain.failed_verification",
      "created_at": 1704894300000,
      "data": {
        "domain_id": "domain_abc123",
        "domain": "example.com",
        "reason": "DNS records not found"
      }
    }
    ```
  </Accordion>

  <Accordion title="domain.removed">
    Triggered when a domain is removed from your account.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_domain123_removed",
      "type": "domain.removed",
      "created_at": 1704894310000,
      "data": {
        "domain_id": "domain_abc123",
        "domain": "example.com"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Contact Events

<AccordionGroup>
  <Accordion title="contact.created">
    Triggered when a new contact is created.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_contact123_created",
      "type": "contact.created",
      "created_at": 1704894320000,
      "data": {
        "contact_id": "contact_abc123",
        "email": "user@example.com",
        "phone_number": "+1234567890",
        "first_name": "John",
        "last_name": "Doe"
      }
    }
    ```
  </Accordion>

  <Accordion title="contact.updated">
    Triggered when a contact is updated.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_contact123_updated",
      "type": "contact.updated",
      "created_at": 1704894330000,
      "data": {
        "contact_id": "contact_abc123",
        "email": "user@example.com",
        "first_name": "Jane"
      }
    }
    ```
  </Accordion>

  <Accordion title="contact.deleted">
    Triggered when a contact is deleted.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_contact123_deleted",
      "type": "contact.deleted",
      "created_at": 1704894340000,
      "data": {
        "contact_id": "contact_abc123",
        "email": "user@example.com"
      }
    }
    ```
  </Accordion>

  <Accordion title="contact.subscribed">
    Triggered when a contact opts in to receive emails.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_contact123_subscribed",
      "type": "contact.subscribed",
      "created_at": 1704894350000,
      "data": {
        "contact_id": "contact_abc123",
        "email": "user@example.com",
        "channel": "email"
      }
    }
    ```
  </Accordion>

  <Accordion title="contact.unsubscribed">
    Triggered when a contact unsubscribes from emails.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_contact123_unsubscribed",
      "type": "contact.unsubscribed",
      "created_at": 1704894360000,
      "data": {
        "contact_id": "contact_abc123",
        "email": "user@example.com",
        "channel": "email",
        "reason": "user_request"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### Suppression Events

<AccordionGroup>
  <Accordion title="suppression.added">
    Triggered when an email or phone number is added to the suppression list.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_suppression123_added",
      "type": "suppression.added",
      "created_at": 1704894370000,
      "data": {
        "identifier": "bounced@example.com",
        "identifier_type": "email",
        "suppression_type": "hard_bounce",
        "reason": "mailbox_full"
      }
    }
    ```
  </Accordion>

  <Accordion title="suppression.removed">
    Triggered when an email or phone number is removed from the suppression list.

    **Example Payload:**

    ```json theme={null}
    {
      "id": "evt_suppression123_removed",
      "type": "suppression.removed",
      "created_at": 1704894380000,
      "data": {
        "identifier": "bounced@example.com",
        "identifier_type": "email"
      }
    }
    ```
  </Accordion>
</AccordionGroup>

### SMS Events (Coming Soon)

<SnippetGroup>
  <Snippet title="sms.sent_to_carrier" label="Coming Soon">
    Triggered when an SMS is successfully sent to the carrier.
  </Snippet>

  <Snippet title="sms.delivered_to_handset" label="Coming Soon">
    Triggered when an SMS is delivered to the recipient's handset.
  </Snippet>

  <Snippet title="sms.failed" label="Coming Soon">
    Triggered when SMS delivery fails.
  </Snippet>

  <Snippet title="sms.undelivered" label="Coming Soon">
    Triggered when an SMS cannot be delivered.
  </Snippet>

  <Snippet title="sms.received" label="Coming Soon">
    Triggered when an incoming SMS is received.
  </Snippet>
</SnippetGroup>

## Setting Up Webhooks

<Steps>
  <Step title="Create an Endpoint">
    Create an HTTPS endpoint on your server to receive webhook events
  </Step>

  <Step title="Add Webhook in Dashboard">
    Go to **Settings** → **Webhooks** → **Add Webhook**
  </Step>

  <Step title="Enter URL and Select Events">
    Enter your endpoint URL and choose which events to receive
  </Step>

  <Step title="Test Your Webhook">
    Use the test button to send a sample payload
  </Step>
</Steps>

## Webhook Payload

Example webhook payload:

```json theme={null}
{
  "event": "email.delivered",
  "timestamp": "2025-01-10T14:23:45Z",
  "data": {
    "id": "email_abc123",
    "to": "user@example.com",
    "from": "hello@yourdomain.com",
    "subject": "Welcome!",
    "status": "delivered",
    "deliveredAt": "2025-01-10T14:23:45Z"
  }
}
```

## Handling Webhooks

<CodeGroup>
  ```typescript Express (Node.js) theme={null}
  import express from 'express';
  import { Transmit } from 'transmitdev';

  const app = express();
  app.use(express.json());

  app.post('/webhooks/transmit', async (req, res) => {
    const { event, data } = req.body;

    switch (event) {
      case 'email.delivered':
        console.log(`Email ${data.id} delivered to ${data.to}`);
        break;
      case 'email.bounced':
        console.log(`Email ${data.id} bounced: ${data.bounceReason}`);
        break;
      case 'email.opened':
        console.log(`Email ${data.id} opened by ${data.to}`);
        break;
    }

    res.status(200).send('OK');
  });

  app.listen(3000);
  ```
</CodeGroup>

## Verifying Webhooks

Transmit signs all webhook requests. Verify the signature to ensure authenticity:

```typescript theme={null}
import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhooks/transmit', (req, res) => {
  const signature = req.headers['x-transmit-signature'];
  const secret = process.env.TRANSMIT_WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // Process webhook...
  res.status(200).send('OK');
});
```

## Retries

Transmit will retry failed webhooks:

* Initial retry: after 1 minute
* Second retry: after 5 minutes
* Third retry: after 30 minutes
* Final retry: after 2 hours

<Warning>
  Your endpoint must return a `2xx` status code within 30 seconds to be considered successful.
</Warning>

## Best Practices

<CardGroup cols={2}>
  <Card title="Return 200 Quickly" icon="bolt">
    Process webhooks asynchronously. Return 200 immediately, then process in background.
  </Card>

  <Card title="Verify Signatures" icon="shield">
    Always verify webhook signatures to prevent spoofing
  </Card>

  <Card title="Handle Duplicates" icon="copy">
    Webhooks may be delivered more than once. Use idempotency keys.
  </Card>

  <Card title="Log Everything" icon="file-lines">
    Log all webhook events for debugging and auditing
  </Card>
</CardGroup>
