JG Docs
Mechanic

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/config.lua
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:

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:

config/config.webhooks.lua
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 Placed
  • Duty: Status Changed
  • Tuning: Tune Applied via Tablet
  • Servicing: Vehicle Serviced
  • Mechanic: Employee Hired
  • Shop: 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.

config/config.webhooks.lua
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:

config/config.webhooks.lua
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:

  1. A webhookUrl supplied directly by a server-side log entry.
  2. The matching businessEvents entry.
  3. The matching businesses entry.
  4. The matching events entry.
  5. The existing category URL, such as Webhooks.Invoices.
  6. 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:

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:

config/config.webhooks.lua
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:

config/config.webhooks.lua
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-mechanic

Trigger one normal event and one combined business-and-event rule. Confirm each message appears in the expected Discord channel.

Last updated 11 August 2026

On this page