Browse docs

Emergency Dispatch

Public server-side exports and adapter events for Dispatch incidents, calls, and response plans.

Emergency Dispatch

Trusted server resources can create persistent incidents, connect a phone or voice provider, inspect response plans, or continue using the legacy compatibility API.

APIPurpose
CreateDispatchIncident / GetDispatchIncident / CloseDispatchIncidentPreferred resource-owned incident API.
CreateDispatchCall / GetDispatchCall / CloseDispatchCallResource-owned phone and voice call adapter API.
GetDispatchResponsePlans / EvaluateDispatchResponsePlanRead and evaluate configured AAO response plans.
createDispatch / HasDispatch / RemoveDispatchesBySourceAndIdLegacy compatibility API.
These are trusted server-side integration points. Do not forward unvalidated client payloads into them. New integrations should prefer the resource-owned APIs, which derive their namespace from Cfx's invoking resource instead of trusting a caller-supplied provider name.

Resource-owned incidents

CreateDispatchIncident(data)

Creates an idempotent, persistent system incident. Reusing the same sourceId from the same resource returns the existing record instead of creating a duplicate.

FieldTypeRequiredDescription
sourceIdstringYesStable adapter ID: 1–64 letters, numbers, _, ., :, or -.
jobs / jobstring | string[]YesCovered response job or jobs.
coords / location.coordsvector3 | tableYesIncident position with x, y, and z.
message / titlestringYesAt least one incident text field must be present.
centerIdstringNoResponsible center. Every target job must be covered by it.
prioritynumberNoIncident priority.
keywordCode / keywordJobstringNoConfigured response-plan keyword and its owner job.
reportertableNo{ name?, phone?, anonymous? }. Flat reporter fields remain supported.
street, address, poi, destinationstringNoStructured location context.
detailstableNoAdditional incident details.
silentbooleanNoSuppresses audible delivery when true.
authorstringNoTrusted display name for the creating system.
server.lua
local result = exports["sky_jobs_base"]:CreateDispatchIncident({
    sourceId = "bank-alarm:pacific-standard",
    jobs = { "police" },
    coords = { x = 235.0, y = 216.0, z = 106.0 },
    message = "Silent alarm triggered in the main lobby.",
    priority = 1,
    keywordCode = "ARMED_ROBBERY",
    reporter = {
        anonymous = true
    },
    details = {
        alarmZone = "Main lobby"
    }
})

if not result.success then
    print(("Unable to create dispatch incident: %s"):format(result.error))
end

The export returns { success, data?, error? }. The public incident payload omits internal dispatcher ownership tokens, audit state, and mutable runtime tables.

When reporter.anonymous or the top-level anonymous is exactly true, anonymity wins over every supplied name and phone number. Jobs Base clears structured caller identity, including details.callerName and details.callerPhone. Free text is not automatically redacted, so do not place personal data in message, notes, or details.callerSummary for anonymous reports.

GetDispatchIncident(sourceId)

Returns { success = true, data = incident } for the newest active incident owned by the invoking resource. If none is active, it returns that resource's newest archived incident for the ID.

server.lua
local result = exports["sky_jobs_base"]:GetDispatchIncident(
    "bank-alarm:pacific-standard"
)

CloseDispatchIncident(sourceId)

Idempotently requests closure of the invoking resource's incident and returns { success, error? }.

server.lua
local result = exports["sky_jobs_base"]:CloseDispatchIncident(
    "bank-alarm:pacific-standard"
)

A resource cannot read or close another resource's records. Do not add a provider or resource name to the payload; the export captures it at entry.

Phone and voice call adapters

CreateDispatchCall(data)

Adds an incoming or outgoing provider call to the authoritative queue. sourceId is required and idempotent per invoking resource. Supply either centerId or one covered job so Jobs Base can resolve the center.

Optional fields are direction (incoming or outgoing), reporter, the backward-compatible flat reporter fields, notes, incidentId, author, capabilities, and providerControls. Anonymous mode discards both reporter name and phone number before persistence.

server.lua
local result = exports["sky_jobs_base"]:CreateDispatchCall({
    sourceId = "call-88421",
    job = "police",
    direction = "incoming",
    reporter = {
        name = "Alex Morgan",
        phone = "555-0142"
    },
    notes = "Caller reports suspicious activity near Legion Square."
})

if not result.success then
    print(("Unable to create dispatch call: %s"):format(result.error))
end

GetDispatchCall(sourceId) and CloseDispatchCall(sourceId)

GetDispatchCall reads a call created by the same invoking resource. CloseDispatchCall ends it and releases the responsible dispatcher. Both return { success, data?, error? } envelopes.

server.lua
local current = exports["sky_jobs_base"]:GetDispatchCall("call-88421")
local closed = exports["sky_jobs_base"]:CloseDispatchCall("call-88421")

sky_jobs_base:dispatch:callStateChanged

This local server event lets a phone or voice adapter mirror the Dispatch lifecycle into its native line implementation. It is emitted for created, accept, hold, resume, transfer, link_incident, callback, and finish actions.

FieldTypeDescription
id, numbernumber | stringDispatch call identity and display number.
centerIdstringResponsible center.
direction, statusstringCurrent call direction and state.
adapterstringProvider-neutral adapter identifier.
reporterName, reporterPhonestringServer-stored reporter data.
incidentIdnumber?Linked incident, when present.
actionstringLifecycle action that caused the event.
contexttableAction-specific IDs and provider context.
server.lua
AddEventHandler("sky_jobs_base:dispatch:callStateChanged", function(call)
    if call.action == "finish" then
        exports["my_phone"]:EndDispatchLine(call.number)
    end
end)

Response plans

GetDispatchResponsePlans(jobs)

Returns { enabled, plans } for exact configured job names. Each plan contains its owner job, keyword code, requirements, minimum crew, target jobs, and automatic-alarm setting.

server.lua
local catalog = exports["sky_jobs_base"]:GetDispatchResponsePlans({
    "police",
    "ambulance"
})

The export is always registered. When Dispatch is disabled it returns { enabled = false, plans = {} }.

EvaluateDispatchResponsePlan(data)

Evaluates a configured plan against currently staffed virtual units. ownerJob and keywordCode are required; jobs, coords, and minimumCrew are optional.

server.lua
local evaluation = exports["sky_jobs_base"]:EvaluateDispatchResponsePlan({
    ownerJob = "police",
    keywordCode = "ARMED_ROBBERY",
    jobs = { "police" },
    coords = { x = 235.0, y = 216.0, z = 106.0 }
})

if evaluation.eligible then
    for _, unit in ipairs(evaluation.units) do
        print("Suggested unit:", unit.callsign)
    end
else
    print("Response plan unavailable:", evaluation.reason)
end

The result includes eligible, reason, unit and crew coverage, requirements, and selected units. Only available, unassigned units with live crew are considered. With Dispatch disabled the reason is dispatch_disabled.

Legacy compatibility API

createDispatch(title, message, coords, jobs, meta)

Creates a legacy dispatch entry. With Config.Dispatch.enabled = true, it also creates the persistent Dispatch App incident and suppresses the legacy top-center notification. With the master switch disabled, it uses the legacy map dispatch and notification.

jobs accepts one job or group key, or an array of keys. Exact registered job names take precedence over a group with the same key. meta supports source, sourceKey, sourceId, category, keywordCode, priority, silent, reporter, flat reporter fields, anonymous, author, centerId, street, address, poi, destination, and details.

server.lua
local dispatch = exports["sky_jobs_base"]:createDispatch(
    "Vehicle collision",
    "Two vehicles are blocking the eastbound lanes.",
    vector3(1175.2, 2640.4, 37.8),
    { "police", "ambulance" },
    {
        sourceKey = "traffic_control",
        sourceId = "camera-12:event-458",
        category = "traffic_collision",
        priority = 2
    }
)

Returns: the created dispatch entry, or nil when validation or persistent incident creation fails. New adapters should use CreateDispatchIncident, whose namespacing and result envelope are safer and clearer.

HasDispatch(sourceKey, sourceId)

Returns whether a non-completed legacy dispatch exists for the exact source key and ID.

server.lua
local exists = exports["sky_jobs_base"]:HasDispatch(
    "traffic_control",
    "camera-12:event-458"
)

RemoveDispatchesBySourceAndId(sourceKey, sourceId)

Removes every matching legacy dispatch, requests closure of linked Dispatch App incidents, and returns the number of removed entries.

server.lua
local removed = exports["sky_jobs_base"]:RemoveDispatchesBySourceAndId(
    "traffic_control",
    "camera-12:event-458"
)