Installation Guide

Step-by-step setup for oxide-dispatch.

Step-by-step setup for oxide-dispatch.

Prerequisites

Required resources

ResourceMinimum VersionPurpose
ox_liblatestCommands, callbacks, locale, input dialogs
oxmysqllatestDatabase driver
o-linklatestFramework abstraction used by dispatch
FrameworklatestOne of qb-core, qbx_core, or es_extended
FXServera recent versionThe resource includes a small Node.js script and needs the server's built-in Node 22 runtime. Old FXServer builds do not have it and the resource will fail to start — update your server artifact if so.

Supported frameworks

FrameworkSupport
QBCore (qb-core)Full
QBX (qbx_core)Full
ESX Legacy (es_extended)Full

oxide-dispatch expects your o-link setup to provide:

  • Character identifier and name lookup (olink.character.GetIdentifier, olink.character.GetName)
  • Character metadata read/write (olink.character.GetMetadata, olink.character.SetMetadata) — used for callsigns
  • Job lookup (olink.job.Get, olink.job.GetPlayersWithJob)
  • Notify (olink.notify.Send)
  • Callbacks (olink.callback)
  • Optional radial provider (olink.radial.AddItem / RemoveItem) — if your radial provider is registered, the single Dispatch menu appears (Call 911 / 311 for everyone, plus status / callsign / panic entries for responders)
  • Player lifecycle events (olink:server:playerReady, olink:server:playerUnload, olink:server:jobChanged, olink:server:playerDied)

Installation

Place the resource

Place oxide-dispatch inside your server's resources folder.

Add startup order

Start dependencies in order, then dispatch, then any downstream MDT consumer:

server.cfg
ensure ox_lib
ensure oxmysql
# ensure your framework here (qb-core / qbx_core / es_extended)
ensure o-link
ensure oxide-dispatch
# downstream consumers (e.g. oxide-police) start AFTER oxide-dispatch

oxide-dispatch must start after o-link (because it consumes the bridge) and before any resource that reads its alerts (such as an MDT).

Install the SQL schema

Run sql/install.sql against your database before starting the resource.

The install creates:

  • dispatch_alerts — persistent alert records (audit trail, expiry, closure, replies)
  • dispatch_responders — responder attach/detach history per alert

Review configuration

Adjust the live config files:

  • shared/config.lua — debug, broadcast policy, popup behavior, auto-expiry, heatmap
  • shared/config/alerts.lua — the dispatch code catalog
  • shared/config/jobs.lua — responder groups and job mapping
  • shared/config/statuses.lua — per-group responder status lists
  • shared/config/detection.lua — automatic crime detection toggles, weapon blacklist, zone blacklist
  • shared/config/panic.lua — panic subsystem and civilian 911/311 categories
  • shared/config/compat.lua — legacy QB/ESX compatibility shims

See the Configuration Reference for the full reference.

(Optional) Customize keybinds

oxide-dispatch registers two default keybinds via RegisterKeyMapping:

  • G — Accept latest dispatch alert
  • F4 — Panic / Responder Needs Backup

Players can rebind these from the FiveM key bindings menu (FiveM → Settings → Key Bindings → FiveM).

Verify the packaged UI

The manifest points to web/dist/index.html:

fxmanifest.lua
ui_page 'web/dist/index.html'

If you are only installing the resource, no UI build step is required. Rebuild the UI only when editing web/src:

cd web && npm install && npm run build

Framework-Specific Setup

oxide-dispatch ships with shims for legacy police-alert events on QBCore and ESX. Follow the guide that matches your framework — you only need the one that matches the framework you actually run.

oxide-police is the recommended downstream MDT consumer. It reads alerts through the olink.dispatch.* namespace and provides a full police MDT, evidence, and case-management UI on top of dispatch. If you use oxide-police, ensure it loads after oxide-dispatch in your server.cfg.

When oxide-police is running, oxide-dispatch automatically:

  • Defers police duty checks to exports['oxide-police']:IsPlayerOnDuty(source) (fail-open if the call errors)
  • Pulls the active LEO job list from oxide-police's police_departments table via PoliceLookup
  • Publishes per-player statebags oxide-dispatch:isLEO (boolean) and oxide-dispatch:responderGroup (string|nil) for downstream consumers

If you want to hide the Dispatch Hub radial entry on servers using oxide-police's MDT, set Config.DispatchHub.RadialEnabled = false in shared/config.lua. Note: this hides the entry for ALL responder groups (EMS / fire / custom) too — leave it true if you want those groups to keep the hub while LEOs use the MDT.

If you do not use oxide-police, dispatch still works standalone — alerts broadcast to on-duty responders via the in-game popup, and the Dispatch Hub is available to all responder groups including police.

Optional: AI Radio Dispatcher

oxide-dispatch includes optional AI-powered dispatchers — one per framework job (LSPD, BCSO, SASP, AMR EMS, fire, etc.). Officers tune to their department's channel, press PTT, and the AI listens, replies verbally, and files structured alerts through the same pipeline as the rest of the resource.

The feature is enabled in config by default but inactive until you provide an OpenAI API key. To enable it:

Get an OpenAI API key with billing enabled.

Add it as a server convar:

server.cfg
set oxide:ai-dispatch:openai_key sk-...

Use set, not setrset keeps the key on the server only; setr would copy it to every player who connects, exposing your key.

Provision each AI radio channel via your radio system — oxide-police's admin panel if you use it, or any other pma-voice-compatible radio UI. Defaults ship with three channels enabled: 911 = police, 921 = EMS (ambulance), 931 = Fire. Enable or remove others (BCSO / SASP / custom) in shared/config/ai_dispatch.lua as needed.

Each channel's job value must match a job that actually exists on your server, spelled exactly as your framework has it (usually lowercase). If your police job isn't called police (for example lspd), edit channel 911's job in shared/config/ai_dispatch.lua — otherwise no officer will be able to use the 911 AI channel.

Restart oxide-dispatch.

Officer voice audio is transmitted to OpenAI when enabled. Read the privacy notice in the AI Radio Dispatcher guide before turning the feature on.

Full setup, cost notes, privacy disclosure templates, and troubleshooting live in the AI Radio Dispatcher guide.

Verification

Start the server and confirm ox_lib, oxmysql, your framework, o-link, and oxide-dispatch all load without dependency errors.
Confirm the resource is running: type ensure oxide-dispatch in the live server console (or check txAdmin's Resources page) and make sure no red error text appears. On a default install the resource prints no startup message of its own (its boot logs are debug-level and hidden) — no news is good news.
Clock a test player into a responder job (e.g. police).
Run testdispatch 10-71 police from the server console. To use /testdispatch in game instead, the player needs admin permission first — add add_ace group.admin command.testdispatch allow to your server.cfg. Without it, the command silently does nothing.
Confirm the on-duty responder receives a popup alert with sound.
Press G to accept the alert. Confirm the GPS waypoint sets and the responder list updates.
Run /panic from the responder. Confirm a panic alert reaches colleagues in the same group.
From a citizen account, run /911 robbery in progress. Confirm an on-duty officer receives the call.

Notes

Framework Support

oxide-dispatch works on QBCore, QBX, and ESX through o-link. All exports, callbacks, and events behave identically on every supported framework.

Locales

Locale files live in locales/*.json and are loaded through lib.locale(). The shipped locale is en.json. To add another language, drop a <lang>.json next to it and set setr ox:locale <lang> in your server.cfg.

Database character set

The schema uses utf8mb4. Servers running on utf8 (without mb4) may fail on the JSON columns — match the schema or upgrade the database.

Next Steps