Discord Webhooks
A generalized version of the embed style already used in wc_encounter — a clean monospace report inside a code block, action-to-colour mapping, a Discord mention appended below. Green Studio branded by default.
server_scripts only. This module never loads on the client. Webhook URLs and the send logic stay entirely server-side, by construction — not by convention you have to remember.
SendWebhook(source, url, resourceLabel, action, fields?, colorMap?)server
Sends a styled Discord embed describing something a player just did.
| Param | Type | Description |
|---|---|---|
| source | integer | Player the log entry is about. |
| url | string | Discord webhook URL to POST to. |
| resourceLabel | string | Shown as the title prefix — e.g. "Encounter" becomes "Encounter • Completed". |
| action | string | Short key like "complete" — title-cased automatically. |
| fields | { {key, value}, ... } | nil | Ordered array of pairs, rendered as aligned rows. |
| colorMap | { [action] = hexColor } | nil | Per-action colour override. |
Why an array of pairs, not a table? Lua's
{ key = value } tables don't preserve insertion order — so fields takes {{"Money", 50}, {"XP", 10}} instead, to keep your embed rows in the order you wrote them.
example — reward payout log
local colorMap = {
complete = 0x2ECC71, -- green
fail = 0xE74C3C, -- red
decline = 0x9B59B6, -- purple, selfless act
}
wc:SendWebhook(
source,
Config.WebhookUrl,
"Encounter",
"complete",
{
{ "Encounter", "Wagon Breakdown" },
{ "Trust Score", "80/100" },
{ "Money Earned", wc:FormatMoney(50) },
{ "XP Earned", 8 },
},
colorMap
)
Renders as:
resulting embed
Encounter • Completed
```
Player : John Marston
IGN : JohnM_RDR
Character ID : 14
Action : complete
Encounter : Wagon Breakdown
Trust Score : 80/100
Money Earned : $50.00
XP Earned : 8
Time : 14:32:08 2026-06-19
```
Discord: <@123456789012345678>
FormatMoney(value)server
Formats a number as $X.XX, matching the style used throughout wc_lib's own webhook rows.
example
wc:FormatMoney(12.5) -- "$12.50"
How the embed sender picks a path
On VORP, wc_libs prefers Core.AddWebhook when it's available, since that's already the pattern wc_encounter uses. If it's missing, or you're on RSG, it falls back to a manual PerformHttpRequest POST with a Green Studio branded payload — same visual result either way.
Real Wild County example — trader transaction log
wc_trader/server/main.lua
wc:SendWebhook(
src,
GetConvar('wc_trader_webhook', ''),
"Trader",
"sale",
{
{ "Item", itemLabel },
{ "Qty", quantity },
{ "Total", wc:FormatMoney(total) },
}
)
Common mistakes
- Hardcoding a webhook URL directly in a Lua file that ships in your resource — put it behind a server convar or config file that isn't committed to a public repo.
- Putting webhook URLs or send logic in a client file "just this once" —
server_scripts-only is enforced by construction in wc_libs; don't work around it by re-implementing sending on the client. - Passing a plain
{ key = value }table asfields— it won't preserve row order. Use the ordered array-of-pairs form:{{"Key", "Value"}, ...}. - Forgetting to set a per-action entry in
colorMapand being surprised every embed is the same default blue.
Security notes
Security. Store webhook URLs in a server-only convar (
setr wc_trader_webhook "https://..." in a git-ignored server.cfg fragment) or a config file that never ships to the client. A leaked webhook URL lets anyone post fake messages into your Discord as your bot.
Troubleshooting
- If nothing posts to Discord: check the URL isn't empty —
SendWebhooksilently no-ops on a blank/nil URL. - If you see a console error with an HTTP status: check the printed status code — 404 usually means the webhook was deleted in Discord, 401/403 means the URL is wrong or revoked.
- If the embed posts but the Discord mention shows "N/A": the player has no linked
discord:identifier — that's expected for players without Discord linked to their FiveM/RedM account.