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

# Notification Destinations

> Configure Slack, Teams, outbound webhook, and ops-email destinations that receive operational notifications like alert fires and scheduled reports.

<Note>
  **See also**: [Notifications REST API reference](/api-reference/notifications) for request/response shapes, status codes, and error semantics.
</Note>

KaireonAI delivers operational notifications (alert fires, scheduled reports,
health warnings) to configurable destinations. Destinations are configured
once under **Settings → Integrations → Notifications** and reused across
every surface that needs to notify an operator — alert rules, scheduled
reports, and any future ops-facing push.

<Note>
  Notification destinations are **distinct** from customer-facing delivery
  channels (the ones under `/studio/channels`). Channels are for offers and
  creatives; notifications are for operators.
</Note>

## Supported kinds

| Kind                 | Requires                                                  | Use for                                                   |
| -------------------- | --------------------------------------------------------- | --------------------------------------------------------- |
| **Slack**            | Slack incoming webhook URL                                | Channel posts for ops alerts                              |
| **Microsoft Teams**  | Teams incoming webhook URL                                | Adaptive card posts in a Teams channel                    |
| **Outbound Webhook** | URL, optional HMAC secret, optional headers               | Any HTTPS endpoint — PagerDuty, Opsgenie, your own ingest |
| **Ops Email (SES)**  | From address, list of recipient emails, optional reply-to | Broadcast alerts to an ops distribution list              |

All credentials are encrypted at rest using AES-256-GCM (reusing the same
vault as other platform integrations). Slack and Teams webhook URLs are
treated as secrets and redacted when listed.

## Add a destination

1. Open **Settings → Integrations** and switch to the **Notifications** tab.
2. Click **Add Destination**.
3. Select a kind and fill in the kind-specific fields:

<AccordionGroup>
  <Accordion title="Slack">
    1) In Slack, open **Apps → Incoming Webhooks** (or your workspace's App Directory entry for incoming webhooks).
    2) Create a new webhook URL; choose the destination channel.
    3) Copy the webhook URL (starts with `https://hooks.slack.com/services/...`).
    4) In KaireonAI, paste it into the **Webhook URL** field.
    5) Name the destination (e.g., `#ops-alerts`).
    6) Save and click **Test** — a test message should appear in Slack.
  </Accordion>

  <Accordion title="Microsoft Teams">
    1. In Teams, open the target channel → **⋯ → Connectors → Incoming Webhook**.
    2. Create a new webhook; copy the URL (`https://outlook.office.com/webhook/...`).
    3. Paste into the **Webhook URL** field in KaireonAI and save.
    4. Click **Test** — a color-banded adaptive card should appear in the channel.
  </Accordion>

  <Accordion title="Outbound Webhook">
    Use this for any HTTPS receiver: PagerDuty events, Opsgenie ingest, your own
    observability service, an internal alert-bus.

    * **URL** — HTTPS endpoint. Validated against private IP ranges and DNS rebinding before every POST.
    * **Shared Secret** (optional) — when set, each POST includes an `X-Kaireon-Signature: sha256=<hex>` header, HMAC-SHA256 over the exact body.
    * **Headers** (optional) — Additional headers to send (e.g., `Authorization: Bearer ...`). Header names are restricted to `A–Z`, `0–9`, `_`, `-`.

    Verify signatures on your side:

    ```js theme={null}
    const expected = 'sha256=' + crypto.createHmac('sha256', SHARED_SECRET).update(rawBody).digest('hex');
    if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(headerSig))) throw new Error('bad sig');
    ```
  </Accordion>

  <Accordion title="Ops Email (SES)">
    Reuses the platform's existing Amazon SES credentials (configured under
    **Email** in the same Integrations page) — you don't enter credentials
    again here.

    * **From Email** — the sender address for ops notifications (must be SES-verified).
    * **Recipients** — one or more addresses. Every fire sends to the full list.
    * **Reply-To** (optional) — override the reply-to from the email integration.

    The test-connection flow sends a probe to only the first recipient so repeated
    tests don't spam your ops distribution list.
  </Accordion>
</AccordionGroup>

## Payload format

Every adapter receives the same logical `Notification` payload and renders it into its native format:

```ts theme={null}
interface Notification {
  title: string;                          // headline
  body: string;                           // plain text or markdown
  severity: "info" | "warning" | "critical";
  fields?: Array<{ label: string; value: string }>;
  sourceUrl?: string;                     // deep-link back into the app
}
```

* **Slack** renders a `header` + `section` + `fields` + `context` block array, with a severity emoji in the header.
* **Teams** posts a Microsoft message card with a `themeColor` keyed by severity and fields as `facts`.
* **Webhook** POSTs `{ id, timestamp, notification }` as JSON.
* **Ops Email** renders an HTML + plain-text body with a colored severity band.

## Test a destination

The **Test** button on each destination invokes the adapter's
connection-test probe, which sends a harmless message:

* Slack/Teams: posts a "Connection test" message in-channel.
* Webhook: POSTs a test payload; any non-2xx response fails the test.
* Ops Email: sends a test email to only the **first** recipient.

A successful test shows an inline toast; a failure shows the adapter's error
message.

The API equivalent is
`POST /api/v1/notifications/providers/:id/test` — see the
[Notifications API reference](/api-reference/notifications).

## Testing without EventBridge

Notifications do not depend on a cron being wired. You can fire ad-hoc
notifications through three unconditional paths:

1. **Test button** in `/settings/integrations → Notifications` — fires
   the adapter's connection-test probe. This is the fastest smoke
   test and works the moment a destination is saved.
2. **Ad-hoc send API** — `POST /api/v1/notifications/send` with one or
   more `providerIds` and a `notification` payload. Admin-only;
   tenant-scoped. Useful for CI smoke tests, custom automations, and
   manual paging. Full reference at the
   [Notifications API reference](/api-reference/notifications#post-apiv1notificationssend).
3. **Manual alert evaluation** — when you want to exercise the full
   alert-rule path without EventBridge, hit `/api/cron/tick` directly
   with a valid `CRON_TOKEN`. The tick fans out to every enabled rule
   and dispatches notifications through the same providers. See
   [Alert Rules → Triggering evaluation manually](./alert-rules#triggering-evaluation-manually).

Typical example (ad-hoc send):

```bash theme={null}
curl -X POST "$PLATFORM_URL/api/v1/notifications/send" \
  -H "X-API-Key: $KEY" -H "X-Tenant-Id: $TENANT" \
  -H "Content-Type: application/json" \
  -d '{
    "providerIds": ["aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"],
    "notification": {
      "title": "Smoke test",
      "body": "Verifying the Slack adapter from CI.",
      "severity": "info"
    }
  }'
```

Response includes per-provider delivery results:

```json theme={null}
{
  "results": [
    {
      "providerId": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
      "kind": "slack",
      "success": true,
      "providerMessageId": "slack-1714..."
    }
  ]
}
```

## Credential security

* Every sensitive field (webhook URL, HMAC secret, headers) is encrypted with
  AES-256-GCM before persistence in the platform-settings vault.
* The GET list endpoint returns **redacted** configs — secret-like fields are
  replaced with `••••••••`. Operators re-enter secrets on edit.
* Outbound webhook URLs are re-validated on every send via DNS resolution
  checks to prevent DNS rebinding attacks (private/reserved IP ranges are
  rejected).

## Enable / disable and delete

* Each destination has an enable toggle. Disabled destinations are skipped
  when an alert rule fans out notifications.
* Deleting a destination does not delete the alert rules that reference it —
  rule fire attempts will log a "Provider not found" entry and the rule's
  status will be `delivery_failed`.

## Next steps

Once you have at least one destination, go to **Settings → Alert Rules** to
wire thresholds on platform metrics. See [Alert Rules](./alert-rules).

To deliver scheduled reports through these same destinations, see
[Report Schedules](./report-schedules). To automate alert evaluation and
scheduled report runs, see [EventBridge Setup](../self-host/deploy/eventbridge-setup)
(optional during pilot).
