Browse docs

Emergency Dispatch

Set up emergency calls, dispatch units, radio communication, and incident management.

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.

FeatureWhat it provides
Incident overviewActive calls, locations, status, assigned units, logs, and history
Dispatch workspaceUnit suggestions, assignments, response plans, POIs, and incident notes
Emergency intakeA phone app with selectable services, caller information, and location data
Virtual unitsCallsigns, unit types, crew, FMS status, radio channel, and active assignment
Radio HUDChannel control, status buttons, alerts, and direct incident navigation
Audit trailPersistent incident logs and dispatcher actions
The Dispatch App described on this page is the built-in 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:

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:

sky_jobs_base/config/config.lua
Config.Dispatch = {
    enabled = true,
    -- Keep the remaining Dispatch settings from the supplied config.
}
  • enabled = true registers the Dispatch tablet app, radio, Emergency phone app, callbacks, and Job Configurator sections.
  • enabled = false disables the complete integration. Existing createDispatch calls 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:

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

  1. pma-voice
  2. saltychat
  3. yaca-voice

If automatic detection is not possible, select the adapter explicitly:

Voice resourceConfig.voice value
PMA Voice"pma"
SaltyChat"saltychat"
YACA"yaca"
No radio integration"none"
With SaltyChat, enable 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

  1. Run /jobconfig as an administrator.
  2. Select the job you want to configure.
  3. Open Dispatch → Dispatch settings.
  4. Enable Enable dispatch.
  5. Enable Show in Emergency App if citizens may select this service in the phone app.
  6. Enable Enable dispatch center if authorized employees may staff the control center.
  7. Enable Enable emergency assessment if the full incident intake should show medical and danger assessment questions.
  8. Decide whether Notify on-duty staff without units should be used as the last fallback.
  9. Set the estimated response speed used for the displayed arrival time.
  10. 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:

FieldExampleMeaning
Channel ID2500 or POLICE_MAINIdentifier sent to the configured voice adapter
LabelPolice MainName 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:

CodeLabelAvailable for dispatch
1Available by radioYes
2Available at stationYes
3RespondingNo
4On sceneNo
5Request to speakNo
6UnavailableNo

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:

CodeLabelTypical use
PATROLPatrolStandard police unit
CRIMECrime UnitInvestigation unit
EMSAmbulanceMedical response
FIREFire EngineFire suppression
RESCUERescueTechnical 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:

FieldExampleMeaning
CallsignADAM-21Unique radio callsign for this job
Response unit typePATROLOne 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:

FieldExample
Keyword codeROBBERY_ACTIVE
LabelActive robbery
CategoryPolice
Required unitsPATROL:2,CRIME:1
Minimum crew3
Target jobspolice,sheriff
Auto alarmEnabled 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:

ActionTablet or command
Staff a virtual unitSelect a free unit, or run /dispatchunit
Leave the current unitRelease it in Dispatch, or run /dispatchrelease
Join a radio channelOpen Dispatch → Radio and select Join channel
Interact with the radio HUDPress 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:

sky_jobs_base/config/config.lua
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"
}
  • enabled registers or disables the complete phone app.
  • autoDetectCallerNumber resolves the caller's real number server-side through the active phone adapter.
  • allowManualCallbackNumber permits 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

PhoneEmergency appCallback numberAdditional setup
LB Phone / LB Phone UniqueAutomaticAutomaticNone
CodeM PhoneAutomaticAutomaticNone
okokPhoneAutomaticAutomaticNone
17Movement PhoneAutomaticAutomaticNone
YSeriesAutomaticAutomaticNone
QS Smartphone / Smartphone ProAutomaticAutomaticNone
GKS PhoneAutomaticManual fallbackKeep allowManualCallbackNumber = true
RoadPhoneStatic app entryAutomaticAdd 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:

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:

  1. Put a responder on duty with the Dispatch center permission.
  2. Staff a virtual unit and set it to an available FMS status.
  3. Join a configured radio channel.
  4. On a civilian player, open Emergency, select the service, describe the incident, and submit it.
  5. Confirm that the call appears under Incoming emergencies.
  6. Assign the unit, accept the incident on the radio, and verify navigation and status updates.
  7. 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:

client.lua
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

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 messageMeaning and fix
pma was automatically recognized for voice and will be usedNormal 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.luaNo 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.luaNo 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 tabletNormal message. No external tablet provider was selected, so the included Jobs Base tablet is used.
After correcting a provider, do not restart only the job resource. Restart the provider first, then sky_base, and finally sky_jobs_base, because provider selection happens while sky_base starts.