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

# Webhooks

> Receive real-time HTTP notifications from Lettr when emails are delivered, bounced, opened, clicked, or received inbound.

Webhooks provide real-time notifications when events occur in your Lettr account. Instead of polling the API for updates, webhooks push event data to your server the moment something happens—whether an email is delivered, a recipient clicks a link, or an inbound email arrives.

## How Webhooks Work

When an event occurs, Lettr sends an HTTP POST request to your configured endpoint with a JSON payload describing the event. Your server processes the event and responds with a success status code.

<Steps>
  <Step title="Event Occurs">
    An email is sent, delivered, bounced, opened, or received on your inbound domain.
  </Step>

  <Step title="Lettr Sends Webhook">
    An authenticated POST request is sent to your endpoint with the event payload (using your configured auth method).
  </Step>

  <Step title="You Verify & Process">
    Your server verifies authentication, processes the event, and responds with a 2xx status.
  </Step>

  <Step title="Lettr Confirms Receipt">
    Upon receiving a success response, Lettr marks the delivery as complete.
  </Step>
</Steps>

## Use Cases

Webhooks enable powerful real-time integrations:

| Event Type               | Use Case                                                      |
| ------------------------ | ------------------------------------------------------------- |
| `message.delivery`       | Update your database when emails are successfully delivered   |
| `message.bounce`         | Remove invalid addresses from your mailing list               |
| `engagament.open`        | Track engagement metrics and trigger follow-up sequences      |
| `engagament.click`       | Measure link performance and user interest                    |
| `message.spam_complaint` | Immediately suppress users who mark emails as spam            |
| `relay.relay_delivery`   | Process inbound emails, create support tickets, track replies |

## Managing Webhooks

Webhooks can be managed through the Lettr dashboard or the API. The API provides full CRUD access — you can create, list, update, and delete webhooks programmatically.

### Creating a Webhook

<Steps>
  <Step title="Open Webhook Settings">
    Navigate to **Webhooks** in the sidebar.
  </Step>

  <Step title="Click Create Webhook">
    Click the **Create Webhook** button.
  </Step>

  <Step title="Enter Your Endpoint URL">
    Provide the HTTPS URL where Lettr should send event notifications. This must be a publicly accessible endpoint.
  </Step>

  <Step title="Select Events">
    Choose which events to receive. You can subscribe to **all events** or select specific event types from the five categories (Message, Engagement, Generation, Unsubscribe, Relay).
  </Step>

  <Step title="Configure Authentication">
    Optionally set up authentication for webhook deliveries. Lettr supports:

    * **None** — No authentication (not recommended for production)
    * **Basic Auth** — HTTP Basic Authentication with a username and password
    * **OAuth2** — OAuth 2.0 client credentials with client ID, client secret, and token URL
  </Step>

  <Step title="Save">
    Click **Save** to create the webhook. Lettr will begin sending events to your endpoint immediately.
  </Step>
</Steps>

<Card title="Try it in the app" icon="wand-magic-sparkles" href="https://app.lettr.com/webhooks?guide=eyJ2IjoxLCJzdGVwcyI6W3siYW5jaG9yIjoid2ViaG9va3MuY3JlYXRlIiwibWVzc2FnZSI6IkNyZWF0ZSBhIHdlYmhvb2sgaGVyZSB0byBnZXQgcmVhbC10aW1lIGV2ZW50IG5vdGlmaWNhdGlvbnMgaW5zdGVhZCBvZiBwb2xsaW5nIHRoZSBBUEkuIn0seyJhbmNob3IiOiJ3ZWJob29rcy51cmwtaW5wdXQiLCJtZXNzYWdlIjoiRW50ZXIgdGhlIHB1YmxpYyBIVFRQUyBlbmRwb2ludCB3aGVyZSBMZXR0ciBzaG91bGQgUE9TVCBldmVudHMuIEl0IG11c3QgYmUgcmVhY2hhYmxlIGZyb20gdGhlIGludGVybmV0LiJ9LHsiYW5jaG9yIjoid2ViaG9va3Muc3VibWl0IiwibWVzc2FnZSI6IlNhdmUgdG8gc3RhcnQgZGVsaXZlcnkuIFBpY2sgb25seSB0aGUgZXZlbnRzIHlvdSBuZWVkLCBhbmQgYWRkIEJhc2ljIEF1dGggb3IgT0F1dGgyIHRvIHNlY3VyZSB0aGUgZW5kcG9pbnQuIn1dLCJkb2NzIjoiaHR0cHM6Ly9kb2NzLmxldHRyLmNvbS9sZWFybi93ZWJob29rcy9pbnRyb2R1Y3Rpb24ifQ">
  Follow an interactive walkthrough of this guide inside Lettr.
</Card>

### Editing a Webhook

To update a webhook's URL, events, or authentication:

1. Go to **Webhooks**
2. Click on the webhook you want to edit
3. Make your changes
4. Click **Save**

### Enabling and Disabling Webhooks

You can temporarily disable a webhook without deleting it. This is useful during maintenance or when debugging your endpoint:

1. Go to **Webhooks**
2. Find the webhook you want to toggle
3. Click **Enable** or **Disable**

Disabled webhooks stop receiving events but retain their configuration. Re-enabling resumes event delivery.

### Deleting a Webhook

To permanently remove a webhook:

1. Go to **Webhooks**
2. Find the webhook you want to delete
3. Click **Delete** and confirm

<Warning>
  Deleting a webhook is permanent. Any events that occur while no webhook is configured will not be delivered. If you're troubleshooting, consider disabling the webhook instead.
</Warning>

<Note>
  Webhook management (create, update, enable/disable, delete) is available through both the dashboard and the API.
</Note>

## Handling Webhooks

Here's a basic example of a webhook handler in Node.js with Express:

```javascript theme={null}
import express from 'express';

const app = express();

app.post('/webhooks/lettr', express.json(), async (req, res) => {
  try {
    const events = req.body; // Array of event objects

    for (const event of events) {
      const eventType = event.msys ? Object.keys(event.msys)[0] : null;
      const data = eventType ? event.msys[eventType] : null;

      if (!data) continue;

      switch (data.type) {
        case 'delivery':
          await handleDelivery(data);
          break;

        case 'bounce':
          await handleBounce(data);
          break;

        case 'open':
        case 'initial_open':
          await handleOpen(data);
          break;

        case 'click':
          await handleClick(data);
          break;

        case 'spam_complaint':
          await handleSpamComplaint(data);
          break;

        default:
          console.log(`Unhandled event type: ${data.type}`);
      }
    }

    // Always respond with 200 to acknowledge receipt
    res.sendStatus(200);
  } catch (err) {
    console.error('Webhook error:', err.message);
    res.sendStatus(400);
  }
});

async function handleDelivery(data) {
  console.log(`Email delivered to ${data.rcpt_to}`);
  await db.emails.update(data.message_id, { status: 'delivered' });
}

async function handleBounce(data) {
  console.log(`Email bounced: ${data.rcpt_to} - ${data.raw_reason}`);
  await db.suppressions.add(data.rcpt_to, 'bounce');
}

app.listen(3000);
```

## Event Categories

Lettr webhooks are organized into five categories:

### Message Events

Events tracking the delivery lifecycle of emails you send:

* `message.injection` - Email accepted by Lettr and queued for delivery
* `message.delivery` - Email delivered to recipient's mail server
* `message.bounce` - Email bounced (hard or soft)
* `message.delay` - Email delivery temporarily delayed
* `message.out_of_band` - Out-of-band bounce after initial acceptance
* `message.spam_complaint` - Recipient marked email as spam
* `message.policy_rejection` - Email rejected by policy

### Engagement Events

Events tracking recipient interaction with your emails:

* `engagament.open` - Recipient opened the email
* `engagament.initial_open` - First open of the email
* `engagament.click` - Recipient clicked a link
* `engagament.amp_open` - Recipient opened an AMP email
* `engagament.amp_initial_open` - First open of an AMP email
* `engagament.amp_click` - Recipient clicked a link in an AMP email

### Generation Events

Events for message generation failures:

* `generation.generation_failure` - Message failed during generation
* `generation.generation_rejection` - Message rejected during generation

### Unsubscribe Events

Events for recipient opt-outs:

* `unsubscribe.list_unsubscribe` - Recipient unsubscribed via List-Unsubscribe header
* `unsubscribe.link_unsubscribe` - Recipient unsubscribed via a link in the email

### Relay Events

Events for inbound email processing:

* `relay.relay_injection` - Inbound email received and queued
* `relay.relay_delivery` - Inbound email delivered to your endpoint
* `relay.relay_rejection` - Inbound email rejected
* `relay.relay_tempfail` - Inbound email delivery temporarily failed
* `relay.relay_permfail` - Inbound email delivery permanently failed

<Tip>
  Subscribe only to the events you need. This reduces unnecessary traffic and processing on your server.
</Tip>

## Subscribing to Events

When creating a webhook in the dashboard, you choose which events to receive. You can subscribe to all events or select specific event types from the five categories listed above.

## Managing Webhooks via API

The API provides full CRUD access to your webhooks. You can list, create, update, and delete webhooks programmatically.

```bash theme={null}
# List all webhooks
curl -X GET "https://app.lettr.com/api/webhooks" \
  -H "Authorization: Bearer lttr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Get a specific webhook
curl -X GET "https://app.lettr.com/api/webhooks/{webhookId}" \
  -H "Authorization: Bearer lttr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Create a webhook
curl -X POST "https://app.lettr.com/api/webhooks" \
  -H "Authorization: Bearer lttr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order Notifications",
    "url": "https://example.com/webhook",
    "events_mode": "selected",
    "events": ["message.delivery", "message.bounce"],
    "auth_type": "basic",
    "auth_username": "lettr",
    "auth_password": "your-secret"
  }'

# Update a webhook
curl -X PUT "https://app.lettr.com/api/webhooks/{webhookId}" \
  -H "Authorization: Bearer lttr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated Notifications",
    "target": "https://example.com/webhook-v2",
    "events": ["message.delivery", "message.bounce", "engagament.click"],
    "active": true
  }'

# Delete a webhook
curl -X DELETE "https://app.lettr.com/api/webhooks/{webhookId}" \
  -H "Authorization: Bearer lttr_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```

The response for retrieving a webhook includes the configuration and its current status:

```json theme={null}
{
  "message": "Webhook retrieved successfully.",
  "data": {
    "id": "webhook-abc123",
    "name": "Order Notifications",
    "url": "https://example.com/webhook",
    "enabled": true,
    "event_types": ["message.delivery", "message.bounce"],
    "auth_type": "basic",
    "has_auth_credentials": true,
    "last_successful_at": "2024-01-15T10:30:00+00:00",
    "last_failure_at": null,
    "last_status": "success"
  }
}
```

<Tip>
  For complete request and response schemas, see the [Webhooks API Reference](/api-reference/webhooks/list-webhooks).
</Tip>

## Best Practices

<AccordionGroup>
  <Accordion title="Respond Quickly">
    Return a 200 response as soon as possible. If processing takes time, acknowledge receipt immediately and process asynchronously. Lettr waits up to 30 seconds for a response before marking the delivery as failed.
  </Accordion>

  <Accordion title="Verify Authentication">
    Always verify the webhook authentication before processing. Configure Basic Auth or OAuth 2.0 on your webhook and validate credentials in your handler to ensure the request came from Lettr.
  </Accordion>

  <Accordion title="Handle Duplicates">
    Implement idempotency in your handler. Due to retries, you may receive the same event multiple times. Use the event `id` to detect and skip duplicates.
  </Accordion>

  <Accordion title="Use HTTPS">
    Always use HTTPS endpoints. Lettr will not send webhooks to insecure HTTP URLs in production.
  </Accordion>

  <Accordion title="Monitor Failures">
    Set up alerting for webhook failures. The dashboard shows delivery status and recent failures for each webhook.
  </Accordion>
</AccordionGroup>

## Learn More

<CardGroup cols={2}>
  <Card title="Event Types" icon="list" href="/learn/webhooks/event-types">
    Complete reference of all webhook events and payloads
  </Card>

  <Card title="Handling Webhooks" icon="code" href="/learn/webhooks/handling">
    Best practices for processing webhooks reliably
  </Card>

  <Card title="Authorization" icon="lock" href="/learn/webhooks/authorization">
    Secure your endpoints with authentication
  </Card>

  <Card title="Retries" icon="rotate" href="/learn/webhooks/retries">
    Understand retry behavior and failure handling
  </Card>

  <Card title="Testing" icon="flask" href="/learn/webhooks/testing">
    Test webhooks locally and in production
  </Card>
</CardGroup>
