Browse docs
Emergency Dispatch
One dispatch center for every emergency service
Emergency Dispatch adds a shared, server-authoritative control center to the Jobs Base tablet. Police, ambulance, fire, mechanic, and other configured jobs can receive incidents, staff virtual units, use job-specific radio channels, and work with response plans in one synchronized app.
| Feature | What it provides |
|---|---|
| Incident overview | Active calls, locations, status, assigned units, logs, and history |
| Dispatch workspace | Unit suggestions, assignments, response plans, POIs, and incident notes |
| Emergency intake | A phone app with selectable services, caller information, and location data |
| Virtual units | Callsigns, unit types, crew, FMS status, radio channel, and active assignment |
| Radio HUD | Channel control, status buttons, alerts, and direct incident navigation |
| Audit trail | Persistent incident logs and dispatcher actions |
sky_jobs_base system. The optional
Config.EmergencyDispatch block integrates the separate emergencydispatch resource and is not
required for this setup.1. Requirements and start order
Emergency Dispatch requires sky_base, sky_jobs_base, a supported voice resource, and a
configured job resource. A supported phone is required only when citizens should submit calls
through the Emergency phone app.
Start the database, phone, and voice resources before the Sky resources in server.cfg:
ensure oxmysql
ensure <your_phone_resource>
ensure <your_voice_resource>
ensure sky_base
ensure sky_jobs_base
ensure sky_policejob
ensure sky_ambulancejob
ensure sky_firejob
ensure sky_mechanicjob
Use the real resource folder names in place of the placeholders. The start order matters because
sky_base detects providers while it starts.
2. Enable the complete Dispatch system
The master switch is located in sky_jobs_base/config/config.lua:
Config.Dispatch = {
enabled = true,
-- Keep the remaining Dispatch settings from the supplied config.
}
enabled = trueregisters the Dispatch tablet app, radio, Emergency phone app, callbacks, and Job Configurator sections.enabled = falsedisables the complete integration. ExistingcreateDispatchcalls return to the legacy map dispatch and top-center notification.
Restart sky_jobs_base after changing this value.
3. Configure the voice and phone providers
Both providers are selected in sky_base/config/config.lua, not in a job resource and not in
sky_jobs_base:
Config = {
phone = "auto", -- auto, lb, codem, okok, roadphone, yseries, 17mov, qs, ...
voice = "auto", -- auto, none, pma, saltychat, yaca
}
voice = "auto" checks for these started resources in order:
pma-voicesaltychatyaca-voice
If automatic detection is not possible, select the adapter explicitly:
| Voice resource | Config.voice value |
|---|---|
| PMA Voice | "pma" |
| SaltyChat | "saltychat" |
| YACA | "yaca" |
| No radio integration | "none" |
RequestRadioTrafficStates in the SaltyChat config.json. Without it, the
radio channel still works, but the Dispatch HUD cannot reliably display transmitting and receiving
states.Restart the voice resource and then sky_base after changing the provider. Restart
sky_jobs_base afterwards so Dispatch receives the new capabilities.
4. Enable Dispatch for a job
- Run
/jobconfigas an administrator. - Select the job you want to configure.
- Open Dispatch → Dispatch settings.
- Enable Enable dispatch.
- Enable Show in Emergency App if citizens may select this service in the phone app.
- Enable Enable dispatch center if authorized employees may staff the control center.
- Enable Enable emergency assessment if the full incident intake should show medical and danger assessment questions.
- Decide whether Notify on-duty staff without units should be used as the last fallback.
- Set the estimated response speed used for the displayed arrival time.
- Save the job.
Enable dispatch is the per-job master switch. Disabling only Show in Emergency App keeps the
internal Dispatch App available while hiding the job from public callers. Jobs in the crime group
are never listed in the public Emergency app.

5. Create radio channels
Open Dispatch → Radio channels and create at least one channel:
| Field | Example | Meaning |
|---|---|---|
| Channel ID | 2500 or POLICE_MAIN | Identifier sent to the configured voice adapter |
| Label | Police Main | Name displayed in the tablet and radio HUD |

Numeric IDs remain unchanged. PMA Voice maps text IDs to a stable positive number, while SaltyChat uses the text ID and YACA uses it as the slot frequency.
Return to Dispatch settings, select the new channel as Default radio channel, and save. The default remains available as the job or job-group fallback. It does not connect a dispatcher or unit automatically; both join a channel manually from the Radio tab.
6. Create FMS status codes
Open Dispatch → Status codes. Each entry contains:
- Code: the number shown on the radio, for example
1. - Label: the readable status, for example
Available by radio. - Available for dispatch: whether a unit in this status may be suggested or automatically assigned to a new incident.
A practical default set is:
| Code | Label | Available for dispatch |
|---|---|---|
| 1 | Available by radio | Yes |
| 2 | Available at station | Yes |
| 3 | Responding | No |
| 4 | On scene | No |
| 5 | Request to speak | No |
| 6 | Unavailable | No |

At least one status should be marked available. Otherwise, no staffed unit can satisfy a response plan or be suggested for a new call.
7. Create unit types and virtual units
First open Dispatch → Dispatch vehicle types. Create the categories used by response plans:
| Code | Label | Typical use |
|---|---|---|
PATROL | Patrol | Standard police unit |
CRIME | Crime Unit | Investigation unit |
EMS | Ambulance | Medical response |
FIRE | Fire Engine | Fire suppression |
RESCUE | Rescue | Technical rescue |
The code is the stable value referenced by response plans. The label and selected icon are shown to players.

Then open Dispatch → Dispatch fleet data and create the virtual units:
| Field | Example | Meaning |
|---|---|---|
| Callsign | ADAM-21 | Unique radio callsign for this job |
| Response unit type | PATROL | One of the unit types created above |

Dispatch vehicles are virtual. A player does not need to spawn or enter a world vehicle to staff one. Create enough callsigns for the maximum number of units you expect to be active at once.
8. Create keywords and response plans
Open Dispatch → Keywords and response plans. A plan combines an incident keyword with the unit types and jobs required for the response.
Example structure:
| Field | Example |
|---|---|
| Keyword code | ROBBERY_ACTIVE |
| Label | Active robbery |
| Category | Police |
| Required units | PATROL:2,CRIME:1 |
| Minimum crew | 3 |
| Target jobs | police,sheriff |
| Auto alarm | Enabled or disabled |

Write requirements as comma-separated TYPE:COUNT pairs. The type must exactly match a code from
Dispatch vehicle types. Minimum crew counts the personnel staffed on the units selected for the
plan. Auto alarm immediately assigns matching available units when an incident is created with
that keyword.
9. Create POIs and known reporters
Open Dispatch → Dispatch POIs for stations and frequently used incident locations. Enter a name, optional type and address, coordinates, and the announcement radius. Use current location copies the administrator's current X, Y, and Z coordinates.

Known reporters are maintained inside the tablet under Dispatch → Resources → Known reporters. They are persistent and do not need to be added in a Lua config.

10. Grant Dispatch permission
The tablet app requires both of the following:
- The player is on duty for a Dispatch-enabled job.
- The player's grade has the Dispatch center permission (
DISPATCH).
Open the job management permissions for the relevant grade and enable Dispatch center. This permission allows the grade to open the app, create incidents, operate the center, and assign units. If the app is missing for one grade but visible for another, check this permission first.

11. Staff a unit, join radio, and open the radio HUD
Players can work through the tablet or use the supplied commands:
| Action | Tablet or command |
|---|---|
| Staff a virtual unit | Select a free unit, or run /dispatchunit |
| Leave the current unit | Release it in Dispatch, or run /dispatchrelease |
| Join a radio channel | Open Dispatch → Radio and select Join channel |
| Interact with the radio HUD | Press Left Alt or run /dispatchradio |


The FiveM key mapping for the radio can be changed by each player. Radio position, size, button mapping, sounds, and design are stored under Dispatch → Radio settings.

Staffing a unit does not automatically join a radio channel. The player must join one from the Radio tab. The compact radio appears after a channel is active.

12. Configure the Emergency phone app
The global phone-app settings are inside Config.Dispatch.phone:
phone = {
enabled = true,
autoDetectCallerNumber = true,
allowManualCallbackNumber = true,
identifier = "sky_dispatch",
name = "Emergency",
description = "Send a structured emergency report to a local service.",
developer = "Sky-Systems",
icon = "https://cfx-nui-sky_jobs_base/source/html/img/dispatch_emergency_app.svg",
route = "/dispatch-call"
}
enabledregisters or disables the complete phone app.autoDetectCallerNumberresolves the caller's real number server-side through the active phone adapter.allowManualCallbackNumberpermits a manually entered number only when the adapter cannot provide one.
The server validates the selected job, coordinates, and callback number. Browser-submitted values are not trusted directly.


Supported phones
| Phone | Emergency app | Callback number | Additional setup |
|---|---|---|---|
| LB Phone / LB Phone Unique | Automatic | Automatic | None |
| CodeM Phone | Automatic | Automatic | None |
| okokPhone | Automatic | Automatic | None |
| 17Movement Phone | Automatic | Automatic | None |
| YSeries | Automatic | Automatic | None |
| QS Smartphone / Smartphone Pro | Automatic | Automatic | None |
| GKS Phone | Automatic | Manual fallback | Keep allowManualCallbackNumber = true |
| RoadPhone | Static app entry | Automatic | Add the JSON below |
d-phone, the classic qb-phone, and old ESX/gcPhone variants do not expose a custom
iframe app API through the existing adapters. They require a phone-side extension.
RoadPhone setup
Add this object to the AppStore section of roadphone/public/static/config/config.json:
{
"name": "Emergency",
"light_icon": "https://cfx-nui-sky_jobs_base/source/html/img/dispatch_emergency_app.svg",
"dark_icon": "https://cfx-nui-sky_jobs_base/source/html/img/dispatch_emergency_app.svg",
"default": true,
"category": "apps",
"custom_app_id": "sky_dispatch",
"redirect": "custom_app",
"url": "https://cfx-nui-sky_jobs_base/source/html/index.html?skyPhoneRoute=/dispatch-call&skyPhone=roadphone",
"darkmode": true,
"allowJobs": [],
"disallowJobs": [],
"custom_event": {
"active": false,
"closeWhenOpenApp": false
}
}
Keep custom_app_id exactly as sky_dispatch, then restart RoadPhone and sky_jobs_base.
13. Test the complete workflow
Use at least two players for the final test:
- Put a responder on duty with the Dispatch center permission.
- Staff a virtual unit and set it to an available FMS status.
- Join a configured radio channel.
- On a civilian player, open Emergency, select the service, describe the incident, and submit it.
- Confirm that the call appears under Incoming emergencies.
- Assign the unit, accept the incident on the radio, and verify navigation and status updates.
- Add an incident log, close the incident, and confirm that it appears in history.







When no center is staffed, the next available unit receives the incident on its radio. If no unit is available, Notify on-duty staff without units can send the final fallback notification.
Create an incident from another resource
Existing integrations can create a persistent Dispatch incident with the public export. This client-side example sends an incident to the police job and selects a matching response plan:
local coords = GetEntityCoords(PlayerPedId())
exports["sky_jobs_base"]:createDispatch(
"Vehicle theft",
"A vehicle theft was reported by a witness.",
coords,
{ "police" },
{
keywordCode = "VEHICLE_THEFT"
}
)
The job or job-group key must be registered, and keywordCode must match a configured response
plan if you want the plan to be selected automatically.
FAQ
Staff a virtual unit, open Dispatch → Radio, and join a channel. Then press Left Alt or
run /dispatchradio to interact with the compact radio HUD. Players can change the key in the
FiveM key bindings.
Set Config.voice in sky_base/config/config.lua. Use "auto", "pma", "saltychat", or
"yaca". The voice resource must start before sky_base; restart sky_base and
sky_jobs_base after changing it.
Staffing a unit and joining radio are separate actions. Open Dispatch → Radio and select Join channel. Also confirm that the job has at least one channel and that the voice adapter was detected.
Check Config.Dispatch.enabled, the job's Enable dispatch setting, the player's duty state,
and the grade-level Dispatch center permission. Restart sky_jobs_base after changing the
global master switch.
Enable both Enable dispatch and Show in Emergency App for the job. Also check
Config.Dispatch.phone.enabled and the global Dispatch master switch. Crime-group jobs are
intentionally excluded from the public app.
Confirm that a virtual unit has a callsign and matching response type, is currently staffed, has live crew, is not assigned to another incident, and uses an FMS status marked Available for dispatch. Response-plan type codes must match exactly.
Check Config.phone in sky_base, start the phone before sky_base, and keep
autoDetectCallerNumber = true. Enable allowManualCallbackNumber if the selected phone adapter
cannot return a number.
No. The Dispatch fleet is independent of world vehicles. A callsign can be staffed from anywhere.
Typical console messages
Provider detection messages come from sky_base. Check the server console during resource startup;
for client-side radio problems, also check the player's F8 console.
| Console message | Meaning and fix |
|---|---|
pma was automatically recognized for voice and will be used | Normal success message. PMA Voice was started before sky_base. The same format is used for saltychat and yaca. |
Could not detect the voice resource automatically. Radio integration is disabled. Please specify in sky_base/config/config.lua | No supported voice resource was started during detection. Correct the start order or set Config.voice explicitly. |
[sky_base][voice] No supported voice adapter is active. | Dispatch attempted a radio operation without an active adapter. Check Config.voice, the exact resource name, and the start order, then restart sky_base and sky_jobs_base. |
Could not detect the phone automatically. Please specify in sky_base/config/config.lua | No supported phone was detected. Set Config.phone explicitly or correct the phone start order. |
No supported phone resource is active. Phone app integration is disabled. | The Emergency app cannot register through the configured phone adapter. The tablet Dispatch App can still work; only phone integration is disabled. |
sky_jobs_base detected, using included job tablet | Normal message. No external tablet provider was selected, so the included Jobs Base tablet is used. |
sky_base, and finally sky_jobs_base, because provider selection happens while sky_base starts.