Discord Webhook Routing
Route mechanic logs by event and business
This feature is only available from JG Mechanic v1.9 onwards.
Discord webhook routing lets you send different events and mechanic businesses to different Discord channels. Servers that only need one webhook can set a fallback URL and leave the other routing tables empty.
Enable Discord logging
Open config/config.lua and add "discord" to the log types you want to send:
Config.Logs = {
LOG = {
enabled = true,
destinations = { "console" }
},
EVENT = {
enabled = true,
destinations = { "discord" }
},
SECURITY = {
enabled = true,
destinations = { "console", "ox_lib", "discord" }
}
}Routing only changes the Discord destination. It doesn't affect console or ox_lib.
Use one webhook
Set fallback in config/config.webhooks.lua:
Webhooks.DiscordSettings.routing = {
fallback = "https://discord.com/api/webhooks/WEBHOOK_ID/WEBHOOK_TOKEN",
events = {},
businesses = {},
businessEvents = {}
}The fallback receives any Discord log that doesn't match another route.
Existing category URLs such as Webhooks.Invoices and Webhooks.Orders still work. They take priority over fallback. Leave those category URLs empty if every log should use the same fallback webhook.
Route one event
Add the exact event title to events. The event title is the title shown in the Discord embed.
This sends paid invoices to one channel and all other unmatched logs to the fallback:
Webhooks.DiscordSettings.routing = {
fallback = "https://discord.com/api/webhooks/DEFAULT_ID/DEFAULT_TOKEN",
events = {
["Invoices: Invoice Paid"] = "https://discord.com/api/webhooks/INVOICE_ID/INVOICE_TOKEN"
},
businesses = {},
businessEvents = {}
}Other event titles include:
Orders: Order PlacedDuty: Status ChangedTuning: Tune Applied via TabletServicing: Vehicle ServicedMechanic: Employee HiredShop: Item Purchased
Event titles are case-sensitive.
Route one business
Add the mechanic's config name to businesses. This is the key used inside Config.MechanicLocations, such as bennys or lscustoms.
You can also use the framework job name configured for that mechanic. JG Mechanic checks the mechanic config name first, then its job name.
Webhooks.DiscordSettings.routing = {
fallback = "https://discord.com/api/webhooks/DEFAULT_ID/DEFAULT_TOKEN",
events = {},
businesses = {
bennys = "https://discord.com/api/webhooks/BENNYS_ID/BENNYS_TOKEN",
mechanic = "https://discord.com/api/webhooks/MECHANIC_ID/MECHANIC_TOKEN"
},
businessEvents = {}
}Every event for bennys uses the first URL. Events for a mechanic whose framework job is mechanic use the second URL unless a config-name route matches first.
Combine a business and event
Put the event inside the matching business entry in businessEvents:
Webhooks.DiscordSettings.routing = {
fallback = "https://discord.com/api/webhooks/DEFAULT_ID/DEFAULT_TOKEN",
events = {
["Invoices: Invoice Paid"] = "https://discord.com/api/webhooks/ALL_INVOICES_ID/ALL_INVOICES_TOKEN"
},
businesses = {
bennys = "https://discord.com/api/webhooks/BENNYS_ID/BENNYS_TOKEN"
},
businessEvents = {
bennys = {
["Invoices: Invoice Paid"] = "https://discord.com/api/webhooks/BENNYS_INVOICES_ID/BENNYS_INVOICES_TOKEN"
}
}
}A paid invoice for bennys uses the combined route. Other bennys events use the business route. Paid invoices for other businesses use the event route. Anything else uses a matching legacy category URL, then fallback.
Routing priority
JG Mechanic checks routes in this order:
- A
webhookUrlsupplied directly by a server-side log entry. - The matching
businessEventsentry. - The matching
businessesentry. - The matching
eventsentry. - The existing category URL, such as
Webhooks.Invoices. routing.fallback.
Blank or missing entries are skipped. If no URL matches, the Discord log is skipped. Other configured destinations still receive it.
Migrate from v1.6.6
Keep category URLs working
Copy the existing URLs from your old server/sv-webhooks.lua into the same category keys in config/config.webhooks.lua:
Webhooks.SelfService = ""
Webhooks.Orders = ""
Webhooks.TabletTuning = ""
Webhooks.Servicing = ""
Webhooks.Invoices = ""
Webhooks.Mechanic = ""
Webhooks.Admin = ""These keys remain compatible. You don't need to move them into routing unless you want more specific rules.
Move event rules
If your old sendWebhook() customisation selected a URL from the webhook title, add that title to routing.events:
events = {
["Invoices: Invoice Paid"] = "https://discord.com/api/webhooks/INVOICE_ID/INVOICE_TOKEN",
["Orders: Order Placed"] = "https://discord.com/api/webhooks/ORDER_ID/ORDER_TOKEN"
}Move business rules
If your old function selected a URL from a mechanic config name or job, move those URLs into routing.businesses. Use routing.businessEvents when the old rule checked both values:
businesses = {
bennys = "https://discord.com/api/webhooks/BENNYS_ID/BENNYS_TOKEN"
},
businessEvents = {
bennys = {
["Invoices: Invoice Paid"] = "https://discord.com/api/webhooks/BENNYS_INVOICES_ID/BENNYS_INVOICES_TOKEN"
}
}Restart and test
Restart jg-mechanic:
restart jg-mechanicTrigger one normal event and one combined business-and-event rule. Confirm each message appears in the expected Discord channel.
Last updated 11 August 2026