# Webhook Relays

## Overview

Webhook Relays let you forward webhook payloads from external services directly into a Roam group chat, without writing any code. Each relay provides a unique URL that accepts POST requests with a JSON payload and posts the content to your configured recipients.

```
┌─────────────┐         ┌─────────────────┐         ┌──────────────┐
│  PagerDuty  │         │  Webhook Relay  │         │  Roam Group  │
│  Grafana    │──POST──▶│  (unique URL)   │───msg──▶│  Chat        │
│  Sentry ... │         │                 │         │              │
└─────────────┘         └─────────────────┘         └──────────────┘
   Your service       Templates, filters,         Your team sees
  sends a webhook      and colors applied         the notification
```

This is ideal for receiving notifications from services like PagerDuty, Grafana, Sentry, Datadog, GitHub, or any tool that supports outgoing webhooks.

With Webhook Relays you can:

- **Template messages** using fields from the incoming payload
- **Add buttons** that link back to the source service
- **Color-code messages** to indicate severity or status
- **Override colors dynamically** based on payload values
- **Filter delivery** so only matching payloads produce messages

## Create a Webhook Relay

1. In Roam, navigate to **Roam Administration > Integrations > Webhook Relays**.
2. Click **Add** and enter a name and optional description for the relay.
3. After creation, the relay's unique **Webhook URL** is displayed. Copy it — you'll paste this into your external service.

The URL is a secret. Anyone with the URL can post messages to your chat, so treat it like a credential.

## Add Recipients

Under **Webhook Message Recipients**, add the groups or individuals that should receive relay messages. You can target:

- **Groups** — Messages appear in the group chat.
- **Individuals** (by email) — Messages are delivered to a direct conversation.

## Configure the Message

The template editor lets you customize how incoming payloads are displayed.

### Message Text

Write your message using Markdown. Insert fields from the payload using `{{field}}` placeholders. Use **Insert Field** to pick from fields found in the sample payload.

For example, given this payload:

```json
{
  "title": "CPU usage above 90%",
  "source": "monitor-1",
  "url": "https://app.datadoghq.com/monitors/123"
}
```

A template like:

```
**{{title}}**
Source: `{{source}}`
```

produces:

> **CPU usage above 90%**
> Source: `monitor-1`

Nested fields are accessed with dot notation: `{{event.data.id}}`.

### Buttons

Add buttons that appear below the message. Each button has a **label** and a **URL**. Button URLs can also use `{{field}}` placeholders — for example, `{{url}}` to link back to the alert in your monitoring tool.

## Set a Color

Choose a color that renders as a vertical strip on the left side of the message. Pick from presets:

| Preset | Color |
|--------|-------|
| **Good** | Green |
| **Warning** | Yellow / amber |
| **Danger** | Red |

Or toggle **Use Custom Color** to enter any hex color (e.g. `#5B3FD9`).

## Color Override Rules

Color overrides let you dynamically change the message color based on payload values. Each rule specifies:

1. A **field** from the payload (e.g. `status`)
2. A **match value** (e.g. `critical`)
3. A **color** (Good, Warning, or Danger)

The first matching rule wins. If no rules match, the base color is used.

**Example:** For an alerting service that sends a `severity` field:

| Field | Value | Color |
|-------|-------|-------|
| `severity` | `critical` | Danger |
| `severity` | `warning` | Warning |
| `severity` | `ok` | Good |

This way, critical alerts appear with a red strip and resolved alerts appear green — all from the same relay.

## Delivery Conditions

By default, every incoming webhook produces a message. Delivery conditions let you filter so that only matching payloads are delivered.

Each condition specifies:

1. A **field** from the payload (e.g. `action`)
2. An **operator** (see table below)
3. One or more **values**

The available operators are:

| Operator | Description |
|----------|-------------|
| is | Exact match against a single value |
| is not | Negated exact match against a single value |
| is one of | Matches any value in a comma-separated list |
| is not one of | Matches none of the values in a comma-separated list |
| contains | Substring match against a single value |
| does not contain | Negated substring match against a single value |

All conditions must match for the message to be delivered. Payloads that don't match are still captured (updating the sample payload and last-received timestamp) but no message is sent.

**Example:** Only deliver when `severity` is one of `high, critical`:

| Field | Operator | Values |
|-------|----------|--------|
| `severity` | is one of | `high`, `critical` |

**Example:** Only deliver when the `message` field contains `error`:

| Field | Operator | Values |
|-------|----------|--------|
| `message` | contains | `error` |

This prevents low-priority noise from flooding your chat while still capturing all payloads for debugging.

## Sender Profile Image

Optionally upload a custom avatar that appears as the sender's profile image for relay messages. This helps distinguish different relays at a glance — for example, using the PagerDuty logo for PagerDuty alerts.

## Sample Payload

The first webhook received by a new relay is automatically captured as the **sample payload**. This sample powers the **Insert Field** button, which lists available fields and shows example values from the captured payload.

If the payload structure changes (e.g. you switch to a different event type), click **Clear** to discard the sample. The next incoming webhook will be captured as the new sample.

## Connect Your External Service

In your external service's webhook or notification settings, paste the relay's Webhook URL as the destination. The relay accepts `POST` requests with a JSON body.

Common services with outgoing webhook support:

- **PagerDuty** — Events & Incidents webhooks
- **Grafana** — Contact point webhooks
- **Sentry** — Issue & error alert webhooks
- **Datadog** — Monitor notification webhooks
- **GitHub** — Repository webhooks (push, PR, issues, etc.)
- **GitLab** — Project webhooks
- **Jira** — Automation webhooks
- **Stripe** — Event webhooks

Any service that can send a `POST` request with a JSON body to a URL will work.

## Example: PagerDuty Incident Alerts

Here's a complete example setting up a relay for PagerDuty incident notifications.

**1. Create a relay** named "PagerDuty Alerts" and add your ops group as a recipient.

**2. In PagerDuty**, add a Generic Webhook (v3) integration and paste the relay URL.

**3. Trigger a test incident** so PagerDuty sends a payload. The relay captures it as the sample. A PagerDuty payload looks like:

```json
{
  "event": {
    "event_type": "incident.triggered",
    "data": {
      "title": "Disk usage above 90%",
      "urgency": "high",
      "status": "triggered",
      "html_url": "https://your-org.pagerduty.com/incidents/Q1EXAMPLE"
    }
  }
}
```

**4. Configure the message template:**

```
**{{event.data.title}}**
Status: {{event.data.status}} · Urgency: {{event.data.urgency}}
```

Add a button with label "View in PagerDuty" and URL `{{event.data.html_url}}`.

**5. Add color override rules:**

| Field | Value | Color |
|-------|-------|-------|
| `event.data.status` | `triggered` | Danger |
| `event.data.status` | `acknowledged` | Warning |
| `event.data.status` | `resolved` | Good |

**6. Add a delivery condition** to only deliver high-urgency incidents:

| Field | Operator | Values |
|-------|----------|--------|
| `event.data.urgency` | is one of | `high` |

Now your ops group receives color-coded PagerDuty alerts for high-urgency incidents, with a direct link back to PagerDuty.

## HTTP Response Codes

When an external service posts to a relay URL, the following responses are returned:

| Status | Meaning |
|--------|---------|
| `200 OK` | Payload accepted and message delivered (or captured if relay is disabled) |
| `400 Bad Request` | Request body is not valid JSON |
| `404 Not Found` | Relay URL does not exist |
| `413 Payload Too Large` | JSON payload exceeds the size limit |
| `429 Too Many Requests` | Rate limit exceeded — retry after the indicated period |