Browse docs

Exports

Client and server exports provided by the Sky Police Job resource, including the safe Advanced Speed Camera boundary.

This page documents the supported public integration calls. Client values are never authoritative for police permissions, review decisions, evidence, offences, or billing.

Server Exports

Dispatch

Create a dispatch for the MDT Tablet.

exports["sky_jobs_base"]:createDispatch(
    "Suspicious activity", -- title
    "Caller reports suspicious behavior near Legion Square.", -- description
    GetEntityCoords(PlayerPedId()), -- coords (vector3)
    { "police", "sheriff" } -- jobs
)

Restraints

These are compatibility forwards to the shared sky_jobs_base interaction system. Police jobs from Config.Jobs are registered automatically. For any other job resource, call registerInteractionJobs from a server script before using these exports. The acting player's job, duty policy, target distance/state, and configured item requirements are validated server-side; calling a Police Job export does not bypass them.

See the Sky Jobs Base server exports for registration, permissions, and the preferred shared exports.

Police keeps compatibility forwards for cuffs, zipties, and escort. Leg restraints and head bags are owned exclusively by Jobs Base; call the corresponding sky_jobs_base exports directly.

cuffPlayer(sourceId, targetId, cuffType?, options?)

  • Purpose: Applies cuffs or zipties to a target player from another resource.
  • Arguments:
    • sourceId (number): The server ID of the acting player.
    • targetId (number): The server ID of the target player.
    • cuffType (string?): "cuffs" (default) or "zipties".
    • options (table?):
      • ignoreItemCheck (boolean?) — skip the restraint item requirement and consumption.
      • allowSelf (boolean?) — allow sourceId == targetId.
  • Returns: boolean, string? — true on success, otherwise false and a reason key.
local success, reason = exports["sky_policejob"]:cuffPlayer(sourceId, targetId, "cuffs", {
    ignoreItemCheck = false,
    allowSelf = false
})

uncuffPlayer(sourceId, targetId, options?)

  • Purpose: Removes cuffs or zipties from a target player.
  • Returns: boolean, string?.
local success, reason = exports["sky_policejob"]:uncuffPlayer(sourceId, targetId)

cutZipties(sourceId, targetId, options?)

  • Purpose: Cuts zipties from a target player.
  • Returns: boolean, string?.
local success, reason = exports["sky_policejob"]:cutZipties(sourceId, targetId)

isPlayerCuffed(targetId)

  • Purpose: Reports whether the target player is currently restrained.
  • Returns: boolean.
local cuffed = exports["sky_policejob"]:isPlayerCuffed(targetId)

Escort

escortToggle(sourceId, targetId)

  • Purpose: Starts or stops escorting the target player.
  • Returns: boolean, string?.
local success, reason = exports["sky_policejob"]:escortToggle(sourceId, targetId)

escortPutInVehicle(sourceId, targetId, netId?, seat?)

  • Purpose: Places the escorted player into a vehicle. Without netId the closest valid vehicle is used.
  • Returns: boolean, string?.
local success, reason = exports["sky_policejob"]:escortPutInVehicle(sourceId, targetId)

escortTakeOutVehicle(sourceId, targetId)

  • Purpose: Takes the escorted player out of a vehicle.
  • Returns: boolean, string?.
local success, reason = exports["sky_policejob"]:escortTakeOutVehicle(sourceId, targetId)

Jail

isPlayerInPrison(playerId)

  • Purpose: Reports whether the player is currently serving a jail sentence.
  • Returns: boolean.
local imprisoned = exports["sky_policejob"]:isPlayerInPrison(playerId)

Devices and tracking

GetCctvCameras(jobName?)

  • Purpose: Returns the deployed CCTV cameras, optionally filtered to one police job.
  • Returns: table — camera records.
local cameras = exports["sky_policejob"]:GetCctvCameras("police")

GetSpeedcamCameras()

  • Purpose: Returns the deployed speed cameras.
  • Returns: table — camera records.
local speedcams = exports["sky_policejob"]:GetSpeedcamCameras()

GetMapTrackers()

  • Purpose: Returns the currently broadcast GPS trackers and ankle monitors (the data shown on the police map).
  • Returns: table — tracker records.
local trackers = exports["sky_policejob"]:GetMapTrackers()

GetWheelClampOnVehicle(vehicleOrNetId, plate?)

  • Purpose: Returns the wheel clamp attached to a vehicle, resolved by entity/net ID or plate.
  • Returns: table | nil — { attached = true, netId, plate, wheelBone } or nil when no clamp is attached.
local clamp = exports["sky_policejob"]:GetWheelClampOnVehicle(netId)
if clamp then
    print(clamp.plate, clamp.wheelBone)
end

Usable items

useItem(source, itemName, payload?)

  • Purpose: Triggers a registered Police-specific usable-item handler for a player. Use this when your inventory or another resource wants to run a Police item such as gps_tracker without going through RegisterUsableItem. Shared restraint items belong to sky_jobs_base.
  • Returns: boolean — true when a handler ran successfully; prints an English debug message when no handler is registered for the item.
exports["sky_policejob"]:useItem(source, "gps_tracker")

Manual tablet registry exports

When Config.PoliceTablet.autoFillFromDatabase.citizens = false and/or Config.PoliceTablet.autoFillFromDatabase.vehicles = false, other scripts can manage the manual tablet registry entries through server exports.

If the matching autofill setting is still enabled, these exports return:

{
    success = false,
    error = "auto_fill_enabled"
}

Citizens

Create a manual citizen profile entry.

server.lua
local result = exports["sky_policejob"]:RegisterCitizen({
    identifier = "char1:abcd",
    name = "Max Mustermann",
    gender = "male",
    dob = "1999-04-15",
    job = "Unemployed",
    tags = { "Wanted" },
    notes = {
        { title = "Note", text = "Manual record" }
    },
    fingerprint = "FP-12345",
    dna = "DNA-12345"
})

Update an existing manual citizen profile entry.

server.lua
local result = exports["sky_policejob"]:UpdateCitizen({
    identifier = "char1:abcd",
    name = "Max Mustermann",
    image_url = "https://example.com/citizen.png",
    tags = { "Wanted", "VIP" }
})

Read or delete a manual citizen profile entry.

server.lua
local citizen = exports["sky_policejob"]:GetCitizen("char1:abcd")
local deleted = exports["sky_policejob"]:DeleteCitizen("char1:abcd")

Supported citizen payload fields:

  • identifier
  • name
  • gender
  • dob
  • job
  • image_url or url
  • image_id
  • tags
  • notes
  • fingerprint
  • dna

Vehicles

Create a manual vehicle profile entry.

server.lua
local result = exports["sky_policejob"]:RegisterVehicle({
    plate = "B-EMS-12",
    model = "ambulance",
    owner_name = "Sky Medical",
    owner_identifier = "society:ambulance",
    color = {
        primary = "white",
        secondary = "red"
    }
})

Update an existing manual vehicle profile entry.

server.lua
local result = exports["sky_policejob"]:UpdateVehicle({
    plate = "B-EMS-12",
    tags = { "Fleet" },
    cases = { "CASE-1024" },
    notes = {
        { title = "Storage", text = "Assigned to EMS fleet" }
    }
})

Read or delete a manual vehicle profile entry.

server.lua
local vehicle = exports["sky_policejob"]:GetVehicle("B-EMS-12")
local deleted = exports["sky_policejob"]:DeleteVehicle("B-EMS-12")

Supported vehicle payload fields:

  • plate
  • model
  • ownerName or owner_name
  • ownerIdentifier or owner_identifier
  • color
  • image_url or url
  • image_id
  • tags
  • notes
  • cases

Weapons

Create or update a weapon entry in the weapon registry used by the tablet and the weapon checks.

server.lua
local result = exports["sky_policejob"]:RegisterWeapon({
    serialNumber = "SN-4815-1623",
    model = "WEAPON_PISTOL",
    weaponType = "Pistol",
    manufacturer = "Hawk & Little",
    caliber = "9mm",
    ownerIdentifier = "char1:abcd",
    ownerName = "Max Mustermann",
    registrationStatus = "valid",
    expiresAt = "2027-01-01"
})

if result.success then
    print(result.data.weapon.serial_number)
end

Supported weapon payload fields:

  • serialNumber or serial_number (required)
  • model (required)
  • weaponType or weapon_type
  • manufacturer
  • caliber
  • ownerIdentifier or owner_identifier
  • ownerName or owner_name
  • registrationStatus or registration_status — valid, expired, revoked, lost_stolen, or evidence_hold
  • registeredAt or registered_at (YYYY-MM-DD)
  • expiresAt or expires_at (YYYY-MM-DD)

Salary

Pause or resume salary payouts for police employees. These exports are provided by sky_jobs_base and work for all job types.

pausePlayerSalary(playerId)

  • Purpose: Pauses salary payouts for the given player.
  • Returns: boolean — true on success.

resumePlayerSalary(playerId)

  • Purpose: Resumes salary payouts for the given player.
  • Returns: boolean — true on success.

isPlayerSalaryPaused(playerId)

  • Purpose: Checks whether salary payouts are currently paused.
  • Returns: boolean — true if paused.
exports["sky_jobs_base"]:pausePlayerSalary(playerId)
exports["sky_jobs_base"]:resumePlayerSalary(playerId)
local paused = exports["sky_jobs_base"]:isPlayerSalaryPaused(playerId)
See the Sky Jobs Base Server Exports for full documentation and usage examples.

Advanced Speed Camera

Read deployed speed cameras

GetSpeedcamCameras()

Returns the current server-owned camera catalogue. This is a server export and cannot be called directly by a FiveM client.

server.lua
local cameras = exports["sky_policejob"]:GetSpeedcamCameras()

for _, camera in ipairs(cameras) do
    print(camera.id, camera.label, camera.status, camera.limit)
end

Each entry contains:

FieldTypeDescription
idstringDisplay ID such as SP-004
labelstringConfigured camera name
typestringAlways speedcam
statusstringonline, maintenance, or offline
durabilitynumberCurrent server-owned durability
limitnumberConfigured speed limit
tolerancenumberConfigured tolerance
targetnumberInternal numeric camera ID used by supported camera views
coordstableServer-stored world coordinates
headingnumberServer-stored camera heading

Treat the returned table as a snapshot. Changing it does not change the server cache or database.

Review mutations are intentionally private

Advanced review approval and discard are not public exports. The built-in path validates the acting officer's current police job, duty, Boss Menu permission, review ownership, evidence, offence, fine, billing adapter, target player, and review status immediately before mutation.

Do not proxy a raw client event into a server export. If an integration exposes camera information to a client, filter the returned fields and authorize the requesting player first. Review IDs, owner records, evidence, and billing actions must remain server-side.

See Advanced Speed Camera for the complete review and exploit-protection workflow.

Client Exports

Restraints

These exports use the shared sky_jobs_base interaction system. The local player's job must be registered on the server and have the required capability. Police jobs from Config.Jobs are registered automatically; other job resources must use the server-side registerInteractionJobs export first. Calling a client export alone does not whitelist a job.

See the Sky Jobs Base client exports and server whitelist documentation for the preferred shared API.

Police keeps compatibility forwards for cuffs, zipties, and escort. Use the direct Jobs Base exports for leg restraints and head bags.

cuffPlayer(cuffType?)

  • Purpose: Applies cuffs or zipties to the nearest valid player as an officer.
  • Arguments:
    • cuffType (string?): "cuffs" (default) or "zipties".
  • Returns: boolean, string?.
exports["sky_policejob"]:cuffPlayer()

uncuffPlayer()

  • Purpose: Removes cuffs from the nearest player as an officer.
  • Returns: boolean, string?.
exports["sky_policejob"]:uncuffPlayer()

cutZipties()

  • Purpose: Cuts zipties on the nearest player as an officer.
  • Returns: boolean, string?.
exports["sky_policejob"]:cutZipties()

useCuffPlayer(cuffType?) / useUncuffPlayer() / useCutZipties()

  • Purpose: Compatibility aliases for cuffPlayer, uncuffPlayer, and cutZipties. They use the same server-side job whitelist and do not bypass access or item checks.
  • Returns: boolean, string?.
exports["sky_policejob"]:useCuffPlayer("cuffs") -- or "zipties"
exports["sky_policejob"]:useUncuffPlayer()
exports["sky_policejob"]:useCutZipties()

useHandcuffsItem() / useZiptiesItem()

  • Purpose: Runs the full handcuffs/zipties item flow (the same path as using the inventory item), including the item checks.
  • Returns: boolean.
exports["sky_policejob"]:useHandcuffsItem()
exports["sky_policejob"]:useZiptiesItem()

isPlayerCuffed(serverId)

  • Purpose: Checks the locally known cuff state for a player.
  • Returns: boolean.
local cuffed = exports["sky_policejob"]:isPlayerCuffed(serverId)

Escort

escortToggle()

  • Purpose: Starts or stops escorting the nearest player.
  • Returns: boolean, string?.
exports["sky_policejob"]:escortToggle()

escortPutInVehicle()

  • Purpose: Puts the escorted player into the closest vehicle.
  • Returns: boolean, string?.
exports["sky_policejob"]:escortPutInVehicle()

escortTakeOutVehicle()

  • Purpose: Takes the escorted player out of a vehicle.
  • Returns: boolean, string?.
exports["sky_policejob"]:escortTakeOutVehicle()

Jail

openJailMenu()

  • Purpose: Opens the menu to put someone in jail.
exports["sky_policejob"]:openJailMenu()

Radial menu actions

Other resources (e.g. a custom radial menu or keybind resource) can read and trigger the police radial actions instead of using the built-in radial menu. In the built-in menu, currently available actions are grouped into localized person and vehicle submenus.

Available action IDs: handcuff, unhandcuff, ziptie, cut_zipties, leg_restraints, ankle_monitor, head_bag, escort, escort_vehicle, escort_take_out, tackle, tackle_cuff, tackle_release, player_search, carry_patient, impound, park_vehicle, wheel_clamp, wheel_clamp_remove, camera_disassemble, billing, tablet.

getRadialActions()

  • Purpose: Returns every radial action currently offered to the local player, including its availability state.
  • Returns: table — array of action records (id, label, disabled, …). Empty when the radial system is disabled.
local actions = exports["sky_policejob"]:getRadialActions()

getRadialAction(actionId)

  • Purpose: Returns a single radial action record by ID.
  • Returns: table | nil.
local action = exports["sky_policejob"]:getRadialAction("handcuff")

getRadialActionReport()

  • Purpose: Returns all actions plus a per-ID availability map — useful to build an external menu in one call.
  • Returns: table — { actions = { ... }, availability = { [actionId] = { available, disabledReasonKey, disabledReason } } }.
local report = exports["sky_policejob"]:getRadialActionReport()
if report.availability["handcuff"] and report.availability["handcuff"].available then
    -- show the handcuff option
end

isRadialMenuActionAvailable(actionId)

  • Purpose: Checks whether one radial action is currently available.
  • Returns: boolean.
local available = exports["sky_policejob"]:isRadialMenuActionAvailable("impound")

triggerRadialMenuAction(actionId)

  • Purpose: Executes a radial action for the local player.
  • Returns: boolean, table? — true on success, otherwise false and a reason ({ key, fallback }).
local success, reason = exports["sky_policejob"]:triggerRadialMenuAction("player_search")

Usable items

useItem(itemName, payload?)

  • Purpose: Triggers a registered client-side police usable-item handler for the local player.
  • Returns: boolean — true when a handler ran successfully; prints an English debug message when no handler is registered for the item.
exports["sky_policejob"]:useItem("bodycam")

Advanced Speed Camera boundary

No client-side review mutation export

Sky Police Job intentionally does not export client functions for approving or discarding reviews, changing measured speed, replacing a plate, attaching arbitrary evidence, or issuing an invoice. Those actions require server-owned context and remain inside the authenticated tablet workflow.

Detect the open review app

An integration that only needs presentation state can use the shared Jobs Base tablet export.

client.lua
local tablet = exports["sky_jobs_base"]:GetTabletState()

if tablet.open and tablet.appKey == "speedcam_reviews" then
    print("Speed Camera Reviews is open")
end

For deployed camera state, use the read-only client events. For authoritative camera data, call GetSpeedcamCameras() from a server script.

Client code can be inspected and invoked by an exploiter. Never make a billing, evidence, owner, offence, or review decision from a client export result.

Support

Need help? Our support team is always ready to assist.

Join Discord