# Outbound Webhooks

Deliver JSON event notifications to HTTPS endpoints.

Source: https://statusdashboard.com/docs/integrations/webhooks/outbound

> This is a plan-gated feature. If it isn't available in your account, visit the [Billing](/docs/org-mgmt/billing) page or contact support to review your options.

Outbound webhooks deliver JSON event payloads to HTTPS endpoints you control. Register endpoints from [Outbound webhook endpoints](/app/integrations/webhooks/outbound/endpoints), or let visitors subscribe from a status dashboard when the channel is enabled.

For JSON payload format, visibility rules, and delivery logs, see [Webhook notifications](/docs/notifications/webhooks). For the public `/subscribe` flow, see [Webhook subscriptions](/docs/status-dashboards/subscriptions/webhooks).

***

## Signing
Outbound webhooks always include:

| Header           | Value                                   |
| ---------------- | --------------------------------------- |
| `Content-Type`   | `application/json`                      |
| `User-Agent`     | `StatusDashboard-Webhook/1.0`           |
| `X-SD-Signature` | `t=<unix_seconds>,v1=<hmac_sha256_hex>` |

The HMAC is computed over the string `<timestamp>.<raw_request_body>` (UTF-8) with the per-endpoint **signing secret**, using the same algorithm as [inbound webhooks](/docs/integrations/webhooks/inbound).

### How to get the signing secret
| Who                   | When the secret is shown                                                                                                      |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| **Admin**             | Once when you **create** the endpoint (modal). Lost? Use **Rotate signing secret** on the row.                                |
| **Public subscriber** | Once on **successful verification** of the management email. Lost? Open the manage link and choose **Rotate signing secret**. |

The secret is **never** returned from list APIs, manage GET, or email. After a rotate, the previous secret stops verifying immediately.

### Verify a delivery
<CodeBlockTabs defaultValue="Node.js">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="Node.js">
      Node.js
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="Node.js">
    ```js
    const crypto = require('crypto');

    function verifyStatusDashboardSignature(rawBody, signatureHeader, secret) {
      const match = /^t=(\d+),v1=([0-9a-f]+)$/.exec(signatureHeader || '');
      if (!match) return false;
      const ts = parseInt(match[1], 10);
      const received = match[2];
      if (Math.abs(Math.floor(Date.now() / 1000) - ts) > 300) return false; // 5 minutes
      const expected = crypto
        .createHmac('sha256', secret)
        .update(`${ts}.${rawBody}`)
        .digest('hex');
      return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
    }
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    import hmac, hashlib, re, time

    def verify_status_dashboard_signature(raw_body, signature_header, secret):
        match = re.fullmatch(r't=(\d+),v1=([0-9a-f]+)', signature_header or '')
        if not match:
            return False
        ts = int(match.group(1))
        received = match.group(2)
        if abs(int(time.time()) - ts) > 300:  # 5 minutes
            return False
        payload = raw_body if isinstance(raw_body, bytes) else raw_body.encode()
        expected = hmac.new(
            secret.encode(),
            f'{ts}.'.encode() + payload,
            hashlib.sha256,
        ).hexdigest()
        return hmac.compare_digest(expected, received)
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Use the **raw** request body (before JSON parse) for the HMAC.

## Endpoint URL rules
Webhook endpoints must be absolute **HTTPS** URLs on port **443**, with no embedded credentials. Any public host that passes destination validation is accepted. StatusDashboard rejects private, loopback, and link-local destinations.

Endpoint URLs may contain secrets. StatusDashboard stores and displays a redacted **url display** form (host plus a short path hint). The full URL is returned only once on admin create responses. List and update responses use `urlDisplay` and identify rows by a stable **endpoint hash** (`urlHash`).

## Managing subscribers
Organization admins and users with the **subscriber** role can register a **pre-verified** endpoint on [Outbound webhook endpoints](/app/integrations/webhooks/outbound/endpoints). No verification email is sent for admin-created rows.

| Field                      | Meaning                                                                                                                                      |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| **Dashboard**              | Status dashboard the subscription belongs to                                                                                                 |
| **Endpoint URL**           | HTTPS webhook URL (validated per rules above)                                                                                                |
| **Management email**       | Contact for verify/manage flows; receives a **failure alert email** when an endpoint is auto-suppressed (see [Suppression](#suppression))    |
| **Components**             | At least one component on that dashboard                                                                                                     |
| **Pause deliveries**       | When paused, event notifications are skipped for this endpoint until an admin resumes delivery from the edit dialog (pencil icon on the row) |
| **Admin-managed (locked)** | When locked, public subscribe/manage flows cannot change the subscription                                                                    |

Use the **pencil** icon on a row to change components, pause or resume deliveries, or toggle the locked flag. The **list** icon shows the current component selection read-only.

## Suppression
After **5 consecutive** failed event-notification deliveries, StatusDashboard automatically suppresses the endpoint:

* Future deliveries are skipped until suppression is cleared.
* The subscriber row shows a suppressed status.
* The **management email** receives **one alert email** (not one email per failed delivery).

StatusDashboard does **not** email the management address for individual failures before suppression. Use [Webhook delivery logs](/app/notifications/webhooks/logs) to review per-attempt outcomes.

Review or clear suppressed endpoints on [Outbound webhook suppression](/app/integrations/webhooks/outbound/suppression).

### Failure alert email
When suppression triggers, the management email receives a message that webhook notifications were disabled for that endpoint. The email includes:

* The status dashboard name and a **redacted endpoint display** (never the full URL)
* The consecutive failure count that triggered suppression
* The last failure reason when available (for example, `HTTP 503`)
* A **Manage subscription** link when a signed manage URL is available; otherwise instructions to request a new manage link from the status page

Clear suppression entries on [Outbound webhook suppression](/app/integrations/webhooks/outbound/suppression), or unsuspend from the public manage page, after fixing the destination. Clearing suppression does **not** resend missed notifications.

> Suppression blocks delivery to specific 
>   **endpoints**
>    until cleared. It is separate from 
>   **Pause deliveries**
>    (admin edit dialog only) and from turning 
>   **Notifications**
>    off on an event.
