> For the complete documentation index, see [llms.txt](https://tyrix.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://tyrix.gitbook.io/docs/script-resources/tyrix-multi-job/discord-logging.md).

# Discord Logging

Every action a boss can take from the boss menu can be posted to a Discord channel as an embed. **Discord logging** is off by default — nothing is sent until you supply a webhook URL and switch it on.

This is an audit trail, not a notification feed. Each entry names the player who performed the action, the society it affected, and the amounts or ranks involved, so you can answer "who emptied the police account on Tuesday" without opening a database client.

All logging settings live in `shared/config_sv.lua` under `Config_SV.DiscordLogs`.

## Setup

{% stepper %}
{% step %}

### Create a webhook

In Discord, open the channel you want the logs in, then **Channel Settings > Integrations > Webhooks > New Webhook**. Name it, pick the channel, and copy the webhook URL.
{% endstep %}

{% step %}

### Add the webhook URL

Paste that URL into `Config_SV.DiscordLogs.webhook`. It must be the full URL starting with `https://discord.com/api/webhooks/…`, not just the ID or token.
{% endstep %}

{% step %}

### Enable logging

Set `enabled = true`.
{% endstep %}

{% step %}

### Restart the resource

Restart the resource.
{% endstep %}
{% endstepper %}

```lua
Config_SV.DiscordLogs = {
    enabled = true,
    webhook = 'https://discord.com/api/webhooks/000000000000000000/xxxxxxxxxxxxxxxxxxxxxxxx',

    botName = 'Tyrix Multijob',
    botAvatar = '', -- Optional: URL to an image for the bot avatar
}
```

`botName` overrides the webhook's own name for every message this resource sends, so you can point several resources at one channel and still tell them apart. `botAvatar` takes an image URL and is only applied when it is a non-empty string — leave it blank and the webhook keeps whatever avatar you gave it in Discord.

Both the enabled flag and the webhook string are checked on every single log call, so you can blank the webhook to stop logging without touching `enabled`.

{% hint style="warning" %}
A webhook URL is a credential. Anyone who has it can post anything into that channel, including impersonating your log bot. Keep it out of screenshots, support tickets, public repositories and any config bundle you share, and delete the webhook in Discord if you think it has been exposed — rotating it is a two-click job on Discord's side.
{% endhint %}

## What gets logged

Nine log types cover the boss menu. Each fires server-side, after the action has actually been committed and after the boss permission and distance checks have passed — a rejected action produces no log, so the channel is a record of what happened rather than what was attempted.

| Log type     | Fires when                                                                                      |
| ------------ | ----------------------------------------------------------------------------------------------- |
| `hire`       | A boss hires a nearby player into the society from the Employees tab.                           |
| `fire`       | A boss removes an employee from the society.                                                    |
| `promote`    | A boss changes an employee's rank. One type covers both promotions and demotions.               |
| `bonus`      | A boss pays a one-off bonus to an employee out of the society account.                          |
| `deposit`    | A boss deposits money into the society account.                                                 |
| `withdraw`   | A boss withdraws money from the society account.                                                |
| `salary`     | A boss changes the salary attached to a rank. Only reachable when salary management is enabled. |
| `weeklyGoal` | A boss changes the weekly hour goal for a rank.                                                 |
| `moneyWash`  | A boss converts black money to cash through the Money Wash tab.                                 |

`salary` never fires on a default install, because salary management ships disabled — see [Configuration → Boss menu](/docs/script-resources/tyrix-multi-job/configuration.md#boss-menu). `moneyWash` only fires for societies where washing is enabled, which ships as on for every boss menu via `moneywashDefault`.

The four money-moving types (`deposit`, `withdraw`, `bonus`, `moneyWash`) are also written to the in-game transaction ledger that backs the boss menu's Transactions tab, independently of Discord. Turning a Discord log type off does not hide the action in game — see [Database → Columns](/docs/script-resources/tyrix-multi-job/database.md#columns).

## Turning individual logs off

Every type in `logTypes` is toggled independently, and all nine ship `true`. A type set to `false` is dropped before the HTTP request is built, so it costs nothing.

```lua
Config_SV.DiscordLogs.logTypes = {
    hire = true,       -- Employee hired
    fire = true,       -- Employee fired
    promote = true,    -- Employee promoted/demoted
    bonus = true,      -- Bonus given to employee
    deposit = false,   -- Funds deposited to society
    withdraw = true,   -- Funds withdrawn from society
    salary = true,     -- Rank salary changed
    weeklyGoal = false, -- Weekly goal changed
    moneyWash = true,  -- Money washed
}
```

The usual reason to trim this list is volume. On a busy server `deposit` fires constantly as players bank job income, which buries the entries you actually audit — `withdraw`, `bonus` and `fire`. Keeping the withdrawal side on and the deposit side off gives you the interesting half at a fraction of the messages.

Removing a key entirely has the same effect as `false`; the lookup finds nothing and the log is skipped.

## Embed colours

Each log type gets its own embed side-colour, set in `colors`. Values are **decimal integers**, not hex strings — Discord's API takes an integer here, and quoting a `#rrggbb` value will not work.

| Log type     | Shipped value | Colour           |
| ------------ | ------------- | ---------------- |
| `hire`       | `3066993`     | Green `#2ECC71`  |
| `fire`       | `15158332`    | Red `#E74C3C`    |
| `promote`    | `3447003`     | Blue `#3498DB`   |
| `bonus`      | `15844367`    | Gold `#F1C40F`   |
| `deposit`    | `3066993`     | Green `#2ECC71`  |
| `withdraw`   | `15105570`    | Orange `#E67E22` |
| `salary`     | `3447003`     | Blue `#3498DB`   |
| `weeklyGoal` | `9807270`     | Grey `#95A5A6`   |
| `moneyWash`  | `10181046`    | Purple `#9B59B6` |

The defaults are deliberately grouped by consequence rather than by feature: money entering the society is green, money leaving is orange or red, and configuration changes are blue. Deposits and hires share green, and promotions and salary changes share blue, which is fine in practice because the embed title always disambiguates them.

To convert a colour you already have, strip the `#` and read the remaining six hex digits as a base-16 number. `#2ECC71` becomes `3066993`. The config file links a converter if you would rather not do it by hand.

If a log type has no entry in `colors`, the embed falls back to blue (`3447003`), so a typo in a key produces a blue embed rather than a broken message.

```lua
Config_SV.DiscordLogs.colors = {
    fire = 15158332,      -- Red (#E74C3C)
    withdraw = 15105570,  -- Orange (#E67E22)
    moneyWash = 10181046, -- Purple (#9B59B6)
}
```

## What an entry contains

Every embed carries a title describing the action, the colour for its type, a timestamp, and the same four identity fields for the boss who performed it:

| Field          | Value                                                                                                        |
| -------------- | ------------------------------------------------------------------------------------------------------------ |
| Character Name | The in-character name from your framework.                                                                   |
| Steam Name     | The player's connection name as the server sees it.                                                          |
| Discord        | A `@mention` built from the player's `discord:` identifier, or `Not linked` if they are not running Discord. |
| Identifier     | The player's `license:` identifier, or `Unknown` if it could not be read.                                    |

The Discord field is a real mention, which means it pings unless you mute the channel or deny that role the ability to be mentioned. It resolves only for players connected through the Discord-linked FiveM client; anyone who joined without Discord running shows `Not linked`. The license identifier is included as a fallback precisely for those cases — it is the value you can search your own database with.

Each type then appends its own detail fields:

| Log type     | Additional fields                      |
| ------------ | -------------------------------------- |
| `hire`       | Employee, Job                          |
| `fire`       | Employee ID, Job                       |
| `promote`    | Employee ID, Job, New Rank             |
| `bonus`      | Employee, Employee ID, Job, Amount     |
| `deposit`    | Job, Amount, New Balance               |
| `withdraw`   | Job, Amount, New Balance               |
| `salary`     | Job, Rank, New Salary                  |
| `weeklyGoal` | Job, Rank, New Goal                    |
| `moneyWash`  | Job, Dirty Amount, Clean Received, Fee |

Job is the job's label from your framework's `jobs` table, falling back to the raw job name if no label is found. Money values are formatted with a currency symbol and thousands separators. New Balance is the society account balance *after* the transfer, which is what makes the deposit and withdrawal logs useful for reconciling a drained account: the balance chain should be continuous, and a gap means money moved outside the boss menu.

`fire` and `promote` log the employee's identifier rather than their name, because those actions are performed against a roster row and the target may be offline at the time.

The embed layout itself is fixed. What remains yours to control is in `shared/config_sv.lua`: which actions are logged, the colour of each embed, the bot's name and avatar, and the webhook the whole lot is posted to.

## Nothing is arriving

Work through these in order:

* `Config_SV.DiscordLogs.enabled` is `true`. This is the most common cause; the flag ships `false`.
* `webhook` is a complete URL. An empty string, or a URL missing the token segment, is silently skipped.
* The specific `logTypes` key for the action you tested is `true`.
* The action actually succeeded in game. A denied hire, a rejected withdrawal or a failed permission check produces no log, by design.
* The resource was restarted after you edited `config_sv.lua`. Config files are read at start.
* Your server can reach Discord. The resource does not print Discord's response, so a rejected or blocked request fails without a message — check the server console for outbound HTTP or network warnings, and confirm the webhook still exists in Discord (a deleted webhook returns an error nobody sees).

If logging works but entries are missing for one society, check that the society is the one you think it is: the log uses the job label, and two jobs with similar labels are easy to confuse. For anything else, see [Troubleshooting](/docs/script-resources/tyrix-multi-job/troubleshooting.md).
