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

# Automate compromised account response with webhooks

> Set up webhook monitors so MailChannels POSTs a JSON alert to your endpoint the moment a compromised or spamming sender is detected on your network.

When MailChannels detects a compromised account or a sender actively submitting spam, it can POST a JSON notification to an HTTP or HTTPS endpoint you control. This lets you trigger automated remediation — such as scrambling a password, suspending an account, or disabling a plugin — the moment abuse is detected, without requiring manual intervention. Customers who enable webhooks with automated account actions routinely reduce their total outbound volume by two-thirds, because blocked senders stop submitting messages entirely.

Webhooks are a type of Alert Monitor and are available on Standard plan subscriptions and above.

## What MailChannels sends

When a monitor condition is met, MailChannels sends an HTTP POST to your endpoint with a JSON payload in the following structure:

```json webhook payload theme={null}
{
  "condition_name": "sender_id_sending_spam",
  "condition_description": "Sender ID is sending SPAM",
  "account_id": "myhostingcompany",
  "timestamp": "2024-08-15T14:23:00Z",
  "originator": "joe@example.com",
  "originator_type": "x-authuser",
  "sender_id": "myhostingcompany|x-authuser|joe@example.com",
  "ip": "203.0.113.42",
  "transaction_id": "abc123xyz",
  "envelope_sender": "joe@example.com",
  "message_id": "<unique-message-id@example.com>"
}
```

| Field                   | Description                                                             |
| ----------------------- | ----------------------------------------------------------------------- |
| `condition_name`        | Machine-readable name of the alert condition that triggered the webhook |
| `condition_description` | Human-readable description of the condition                             |
| `account_id`            | Your MailChannels account identifier                                    |
| `timestamp`             | ISO 8601 timestamp of when the alert was generated                      |
| `originator`            | The sender hint — typically the authenticated username or email address |
| `originator_type`       | The type of sender hint (for example, `x-authuser`)                     |
| `sender_id`             | The full sender ID string identifying the sender entity                 |
| `ip`                    | The IP address that submitted the message triggering the alert          |
| `transaction_id`        | The ID of the specific transaction that crossed the threshold           |
| `envelope_sender`       | The envelope `MAIL FROM` address of the triggering message              |
| `message_id`            | The `Message-Id` header value of the triggering message                 |

## Verify webhook signatures

Every webhook we send is cryptographically signed, so your endpoint can confirm the alert genuinely came from us and was not altered or forged in transit. Verify the signature before you act on an alert, so a forged or tampered request cannot trigger an account suspension or password reset on your platform.

<Note>
  Verification is optional. We recommend verifying so you can trust an alert before acting on it.
</Note>

Signatures follow the HTTP Message Signatures standard (RFC 9421) using an Ed25519 key, and the request body is covered by a Content-Digest (RFC 9530). Every signed request carries three headers:

| Header            | Purpose                                                                                                                     |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `Content-Digest`  | SHA-256 digest of the raw request body, formatted as `sha-256=:<base64>:`                                                   |
| `Signature-Input` | Signature metadata: the covered component (`content-digest`), the algorithm (`ed25519`), the creation time, and the `keyid` |
| `Signature`       | The Ed25519 signature, under the label `sig1`                                                                               |

The `keyid` in `Signature-Input` tells you which public key to verify against. The current key id is `mcnotifykey`.

### Fetch the public key

Retrieve the public key by its id. The endpoint is public and needs no authentication:

```bash fetch the public key theme={null}
curl 'https://api.mailchannels.net/notifications/v1/webhook/public-key?id=mcnotifykey'
```

It returns the id and the Ed25519 public key in PEM format:

```json public key response theme={null}
{
  "id": "mcnotifykey",
  "key": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n"
}
```

### Verify a request

<Steps>
  <Step title="Fetch and cache the public key">
    Read the `keyid` from the `Signature-Input` header and fetch the matching public key. Cache it rather than fetching on every request, and refresh it periodically so you pick up a future key rotation.
  </Step>

  <Step title="Check the Content-Digest">
    Recompute the SHA-256 digest of the raw request body and confirm it matches the `Content-Digest` header. This proves the body was not modified.
  </Step>

  <Step title="Verify the signature">
    Rebuild the RFC 9421 signature base from the covered `content-digest` component and the signature parameters, then verify the `Signature` against it with the Ed25519 public key. Reject the request if verification fails.
  </Step>
</Steps>

We sign Email API webhooks with the same RFC 9421 scheme, so you can adapt the code in our [Email API webhook verification examples](/email-api/webhooks). Point it at the public key endpoint above and use the `mcnotifykey` key id.

<Tip>
  Treat verification as a gate: only run your automated remediation after the signature checks out. Log and drop any request that is unsigned or fails verification.
</Tip>

## Actions you can take

Your endpoint receives the `sender_id` and other identifying fields and can immediately take action. Common automated responses include:

* **Scramble the password** for the account associated with `originator`, preventing the sender from authenticating further.
* **Block or suspend the account** at the hosting control panel level.
* **Disable the sending plugin** (for example, a WordPress mail plugin) if the `originator_type` indicates a script.
* **Rate-limit the account** at the mail server level to contain the damage while a human investigates.
* **Create a support ticket** or page an on-call engineer using the `sender_id` and `condition_name` fields.

<Tip>
  The more aggressive your automated response, the greater the reduction in spam volume. Even a simple password scramble eliminates all further submissions from that sender without any manual work.
</Tip>

## Configure a webhook monitor

<Steps>
  <Step title="Log in to the Host Console">
    Go to [console.mailchannels.net](https://console.mailchannels.net) and sign in.
  </Step>

  <Step title="Navigate to Monitors">
    Go to **Outbound > Activity > Monitors** and click **Add Monitor**.
  </Step>

  <Step title="Select the alert type">
    Choose the condition you want to monitor from the dropdown menu, such as **Sender ID is sending SPAM** or **Sender ID blocked due to FBL reports**.
  </Step>

  <Step title="Set the alert interval">
    Choose how frequently you want alerts to fire. The interval ranges from **1 to 24 hours**. For compromised account detection, a 1-hour interval gives you the fastest response.
  </Step>

  <Step title="Switch to webhook delivery">
    Change the alert type from the default **Email** to **Webhook**.
  </Step>

  <Step title="Enter your webhook URL">
    Paste the full URL of your endpoint into the text box. Use `https://` to ensure the payload is encrypted in transit. Your endpoint must be publicly reachable and able to return an HTTP 2xx response.

    <Warning>
      If you prefix your URL with `http://` instead of `https://`, the payload is sent without SSL encryption. Always use `https://` for production endpoints.
    </Warning>
  </Step>

  <Step title="Enable and save">
    Check the **Enabled** box to activate the monitor, then click the green check mark to save it.
  </Step>
</Steps>

## Test your endpoint

Before relying on the webhook in production, verify that your endpoint handles the payload correctly. You can test it from the command line with `curl`:

```bash test webhook endpoint theme={null}
curl -X POST https://your-endpoint.example.com/webhook \
  -H "Content-Type: application/json" \
  -d '{
    "condition_name": "sender_id_sending_spam",
    "condition_description": "Sender ID is sending SPAM",
    "account_id": "myhostingcompany",
    "timestamp": "2024-08-15T14:23:00Z",
    "originator": "joe@example.com",
    "originator_type": "x-authuser",
    "sender_id": "myhostingcompany|x-authuser|joe@example.com",
    "ip": "203.0.113.42",
    "transaction_id": "abc123xyz",
    "envelope_sender": "joe@example.com",
    "message_id": "<unique-message-id@example.com>"
  }'
```

Confirm your server logs show the request and that any automated action (account suspension, password change, etc.) fires as expected.

## Routing webhook alerts to Slack

MailChannels webhook payloads cannot be sent directly to a Slack incoming webhook URL because Slack requires a different JSON format. To route alerts to Slack, use an intermediary service such as **Zapier**:

1. Create a Zapier zap with a **Webhooks by Zapier** trigger (catch hook).
2. Use the Zapier webhook URL as your MailChannels webhook destination.
3. Add a Zapier action step that sends a formatted message to your Slack channel.

<Note>
  Webhooks require a Standard plan subscription or higher. If the Monitors section is not visible in your console, upgrade your subscription to unlock webhook notifications.
</Note>
