> For the complete documentation index, see [llms.txt](https://docs.ragnasync.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ragnasync.com/ragnascript/message-routing.md).

# Message Routing

Control where and how each event type sends messages to Discord

The **Message Routes** page on your RagnaSync dashboard lets you control exactly where each event type goes and how it looks in Discord. Think of routes as rules: "When *this event* happens, send it to *this channel* in *this format*."

You'll find it under **Discord > Messages** in your dashboard navigation.

***

## How It Works

Every event type (item drops, monster kills, refine logs, etc.) gets its own section on the Message Routes page. Each section can have one or more **routes** that tell RagnaSync where to send that event.

Click any route (or its **Configure** button) to open its own configuration page, where you set the channel, format, avatar, and conditions — with a live preview on the right showing how the message will look in Discord. Use **Add Route** to create a new one.

A route has five parts:

| Part                | What It Does                                           |
| ------------------- | ------------------------------------------------------ |
| **Format**          | How the message looks (Log, Embed, Narrate, or Custom) |
| **Channel**         | Which Discord channel receives the message             |
| **Avatar**          | The icon shown next to the message                     |
| **Conditions**      | Optional filters to control which events match         |
| **Active/Inactive** | Toggle the route on or off without deleting it         |

### Avatar options

| Option             | What You Get                                       |
| ------------------ | -------------------------------------------------- |
| **Character head** | The player's character sprite (needs a GRF upload) |
| **Initials**       | A coloured circle with the player's initials       |
| **Custom image**   | Your own uploaded image                            |
| **Monster sprite** | The sprite of the monster involved in the event    |
| **None**           | The default RagnaSync webhook avatar               |

{% hint style="info" %}
**Monster sprite** only appears on the four event types that involve a monster — Monster Kills, Item Drops, Homunculus Drops and Mercenary Drops. Other events have no monster to show, so the option is hidden there.

Monsters we don't have a sprite for — a custom monster, or a guardian/emperium, which the client stores as a 3D model rather than a sprite — fall back to the Poring sprite, so the post still looks like a monster event.
{% endhint %}

{% hint style="info" %}
For most event types, a route is created automatically the first time your game server sends that event. **Player Login** and **Player Logout** are the exception — since they fire on every connection, you need to add routes manually if you want Discord notifications.
{% endhint %}

***

## Message Formats

Each route can use a different format. Here's what they look like:

### Log Format

Clean, compact monospace lines — great for high-volume events.

```
💎 Item Drop:     | Marky            | Poring           | Apple                | 5.00%
```

### Rich Embed

Colorful Discord embed cards with structured fields. These are easier to scan and look more polished, and each embed includes a timestamp that automatically displays in every viewer's local timezone — no configuration needed.

### Narrate

A natural-language sentence that reads like a story.

```
Marky obtained an Apple
```

### Custom Message

Build your own format with `{{placeholder}}` syntax. On the route's **Configure** page, set the format to **Custom Message** and a template editor appears.

The editor gives you:

* **Clickable placeholder chips** — just click a field name and it gets inserted at your cursor
* **Live preview** — the preview pane shows how your message will look with sample data as you type

**Example template:**

```
:gem: {{player_name}} got {{item_name}} from {{mob_name}}! ({{rate}})
```

**Result in Discord:**

```
💎 Marky got Apple from Poring! (50.00%)
```

You can use emoji shortcodes like `:gem:`, `:trophy:`, or `:warning:` — they'll automatically convert to real emoji.

{% hint style="info" %}
Each event type has its own set of placeholders. The editor shows all available placeholders for that event type, so you don't need to memorize them.
{% endhint %}

***

## Multi-Channel Routing

You can send the same event to multiple Discord channels by adding more routes. For example, you might want:

* **Item Drops** → `#rare-drops` channel in **Rich Embed** format
* **Item Drops** → `#drop-log` channel in **Log Format** for a compact log

Just click **Add Route** on the event type and pick a different channel.

***

## Condition Filters

Conditions let you narrow down which events trigger a route. Open the route's **Configure** page and expand the **Conditions** section to set up filters.

### How Conditions Work

Each condition has three parts: a **field**, an **operator**, and a **value**.

| Operator   | Meaning       | Example                      |
| ---------- | ------------- | ---------------------------- |
| `=`        | Equals        | `mob_name = Poring`          |
| `!=`       | Not equals    | `item_name != Apple`         |
| `>`        | Greater than  | `rate_raw > 500`             |
| `<`        | Less than     | `rate_raw < 100`             |
| `>=`       | At least      | `refine_to >= 10`            |
| `<=`       | At most       | `refine_from <= 3`           |
| `contains` | Contains text | `player_name contains Admin` |
| `in`       | In list       | `mob_id in 1511,1647,1785`   |

### Condition Groups (AND/OR Logic)

* Conditions **within** the same group use **AND** logic — all must match
* Separate groups use **OR** logic — any group can match

**Example: "Only card drops from MVPs"**

* Group 1: `item_name contains Card` **AND** `rate_raw <= 100`

**Example: "Poring OR Drops card"**

* Group 1: `mob_name = Poring`
* Group 2: `item_name contains Card`

{% hint style="info" %}
The available filter fields depend on the event type. The condition editor only shows fields relevant to that event.
{% endhint %}

***

## Available Filter Fields

Here's what you can filter on for each event type:

### Item Drops (Mob, Homunculus, Mercenary)

| Field         | Description                       |
| ------------- | --------------------------------- |
| `player_name` | Player who got the drop           |
| `mob_name`    | Monster name                      |
| `mob_id`      | Monster ID                        |
| `item_name`   | Dropped item name                 |
| `item_id`     | Dropped item ID                   |
| `rate_raw`    | Drop rate as raw value (100 = 1%) |

### Monster Kills

| Field         | Description             |
| ------------- | ----------------------- |
| `player_name` | Player who got the kill |
| `mob_name`    | Monster name            |
| `mob_id`      | Monster ID              |

### Command Logs

| Field         | Description                 |
| ------------- | --------------------------- |
| `player_name` | Player who used the command |
| `command`     | The @command used           |

### Refine Logs

| Field         | Description               |
| ------------- | ------------------------- |
| `player_name` | Player who refined        |
| `item_name`   | Item being refined        |
| `item_id`     | Item ID                   |
| `refine_from` | Starting refine level     |
| `refine_to`   | Target refine level       |
| `result`      | Outcome (success/failure) |
| `zeny_cost`   | Zeny spent                |

### Shop Transactions

| Field         | Description                 |
| ------------- | --------------------------- |
| `player_name` | Player involved             |
| `type`        | Transaction type (buy/sell) |

### Vending Logs

| Field         | Description |
| ------------- | ----------- |
| `buyer_name`  | Buyer name  |
| `seller_name` | Seller name |

### Container Logs

| Field            | Description                     |
| ---------------- | ------------------------------- |
| `player_name`    | Player who opened the container |
| `container_name` | Container name                  |
| `container_id`   | Container ID                    |
| `item_name`      | Item received                   |
| `item_id`        | Item ID                         |
| `amount`         | Quantity received               |

### Player Login & Logout

| Field         | Description |
| ------------- | ----------- |
| `player_name` | Player name |

### Population Stats

| Field         | Description          |
| ------------- | -------------------- |
| `total`       | Total players online |
| `active`      | Active players       |
| `vending`     | Vending players      |
| `autotrade`   | Autotrade players    |
| `buyingstore` | Buying store players |
| `gm`          | GMs online           |

### Vending Items

| Field         | Description  |
| ------------- | ------------ |
| `player_name` | Seller name  |
| `pos`         | Map location |

***

## When a Channel Gets Deleted

If someone deletes a Discord channel that one of your routes points to, RagnaSync notices and marks it as deleted. In the route list, that route's channel name shows struck-through in red with a **"Discord channel deleted — pick a new one"** note.

Events aimed at a deleted channel are quietly skipped — no retry storms, no Discord errors. The route just sits there waiting for you to decide what to do.

You have two ways to clean it up:

* **Delete the route** — click the trash icon. This is the right move if you don't need that event type going anywhere.
* **Add a new route** — click **Add Route** on the same event and pick a live channel. Then delete the old orphaned one.

{% hint style="info" %}
We don't delete the route for you automatically. Your filters, templates, and conditions often took real thought to set up — if the deletion was a mistake, you can still repoint the route by creating a new one on a live channel and copying your setup over.
{% endhint %}

***

## Example Setups

### MVP-Only Drop Channel

Send only MVP card drops to a special announcement channel:

1. Add a route for **Item Drops** → `#mvp-drops`
2. Set format to **Custom Message**
3. Set template: `:trophy: {{player_name}} got **{{item_name}}** from {{mob_name}}!`
4. Add condition: `rate_raw <= 100`

### Separate Channels for Success/Failure Refines

Route successful refines to one channel and failures to another:

1. Route 1: **Refine Logs** → `#refine-success`, condition: `result = success`
2. Route 2: **Refine Logs** → `#refine-rip`, condition: `result = failure`

### High-Value Vending Alerts

Only log transactions from specific sellers:

1. Route for **Vending Logs** → `#vending-alerts`
2. Add condition: `seller_name = YourMerchant`

### Login/Logout Notifications

Send player connection notifications to a dedicated channel:

1. Add a route for **Player Login** → `#player-activity`
2. Set format to **Custom Message**
3. Set template: `:green_circle: {{player_name}} has logged in!`
4. Repeat for **Player Logout** with: `:red_circle: {{player_name}} has logged out.`
