Browse docs

Client Exports

Client-side exports provided by sky_jobs_base for radial menu, dispatch, and storage interactions.

Player Interactions

The client exports below open or execute the shared handcuff, ziptie, leg-restraint, escort, vehicle, head-bag, and player-search flows.

Calling a client export does not grant access. The player's current job must be registered through the server export registerInteractionJobs, and the server validates the whitelist, duty state, target, distance, restraint state, and required items again when the action is executed. sky_policejob and sky_crimesystem register their configured jobs automatically.

The old civilianUse and skipAccess options are no longer supported. Do not pass them. For another job resource, register its jobs on the server before exposing any of these client actions.

hasInteractionAccess(permission)

Returns boolean, string? for the local player's current server-authoritative whitelist and duty access. Permission names are cuffs, zipties, legRestraints, escort, vehicle, headBag, and search.

local allowed, reason = exports["sky_jobs_base"]:hasInteractionAccess("search")

Handcuffs and zipties

getCuffAvailability(action, options)

Checks whether an action is currently available without executing it.

  • action (string) - cuff, uncuff, ziptie, unziptie, or cut_ziptie.
  • options.targetId (number?) - server ID of a specific target. The nearest player is used when omitted.
  • options.displayOnly (boolean?) - use true while building a menu. Missing cuff, ziptie, or cutter items and the ziptie hands-up execution requirement do not hide the action in this mode. Call the real action export without displayOnly; it validates these requirements and returns the failure reason for the user-facing message.
  • Returns boolean, table? - availability and context or failure information.
local available, context = exports["sky_jobs_base"]:getCuffAvailability("ziptie", {
    targetId = targetId,
    displayOnly = true
})

requestCuff(cuffType, options) and requestUncuff(cuffType, options)

Runs the validated cuff flow for the nearest player or options.targetId.

  • cuffType (string) - cuffs or zipties.
  • Returns boolean, string? - whether the request started and an optional failure reason.
exports["sky_jobs_base"]:requestCuff("zipties", {
    targetId = targetId
})

Nearest-player cuff exports

ExportPurpose
cuffPlayer(cuffType, options?)Applies cuffs or zipties to the nearest valid player.
uncuffPlayer(options?)Removes the nearest player's current restraints.
cutZipties(options?)Cuts the nearest player's zipties with the configured cutter.
isPlayerCuffed(serverId?)Returns whether the selected target or local player is currently cuffed.
useHandcuffsItem()Starts the handcuff item flow.
useZiptiesItem()Starts the ziptie item flow.
getCuffConfig()Returns a read-only snapshot of Config.PoliceCuffs.

useCuffPlayer, useUncuffPlayer, and useCutZipties are compatibility aliases. They use the same job whitelist and do not bypass access checks.

Escape minigame

Escape opportunities are configured through Config.PoliceCuffs.escape in sky_jobs_base/config/config.lua. The server rolls the chance when restraints are applied and owns every minigame round. There is no public client export or event for forcing an escape opportunity or declaring success.

Leg restraints

ExportPurpose
getLegRestraintsAvailability(action, options?)Checks apply or remove for options.targetId or the nearest player.
applyLegRestraints(options?)Applies leg restraints to the selected valid target.
removeLegRestraints(options?)Removes leg restraints from the selected valid target.
isLegRestrained()Returns whether the local player currently has leg restraints.
getLegRestraintsConfig()Returns a read-only snapshot of Config.LegRestraints.
local available = exports["sky_jobs_base"]:getLegRestraintsAvailability("apply", {
    targetId = targetId
})

if available then
    exports["sky_jobs_base"]:applyLegRestraints({
        targetId = targetId
    })
end

The acting job needs the legRestraints permission. The server also validates the target, distance, vehicle state, item requirement, current restraint state, and Config.LegRestraints.requireCuffed.

Escort and vehicle actions

getEscortAvailability(action, options)

  • action (string) - escort, place_in_vehicle, or take_out_vehicle.
  • options.targetId (number?) - specific target for the escort action.
  • Returns boolean, table?.
local available = exports["sky_jobs_base"]:getEscortAvailability("escort", {
    targetId = targetId
})

Escort exports

ExportPurpose
escortToggle()Starts or stops escorting the nearest cuffed player.
escortToggleTarget(targetId, options?)Starts or stops escorting a specific cuffed player.
escortPutInVehicle()Places the currently escorted player in the nearest valid vehicle.
escortTakeOutVehicle()Removes a cuffed player from the nearest vehicle.
escortPlaceInVehicle(options?)Availability-driven variant used by menu integrations.
escortRemoveFromVehicle(options?)Availability-driven removal variant.
getEscortConfig()Returns a read-only snapshot of Config.PoliceEscort.

The escort and vehicle permissions are separate. A job can be allowed to escort players without being allowed to place them in or remove them from vehicles.

Head bag

ExportPurpose
getHeadBagAvailability(action, options?)Checks apply or remove for options.targetId or the nearest player.
applyHeadBag(options?)Applies a head bag to the selected valid target.
removeHeadBag(options?)Removes the selected target's head bag.
useHeadBag(options?)Toggles a head bag on the nearest player or options.targetId.
useHeadBagTarget(options?)Compatibility alias for useHeadBag.
isHeadBagged()Returns whether the local player is currently hooded.
getHeadBagConfig()Returns a read-only snapshot of Config.HeadBag.
exports["sky_jobs_base"]:applyHeadBag({
    targetId = targetId
})

Applying or removing a head bag from another player requires the headBag whitelist permission. A hooded player may still use the configured self-remove flow.

ExportPurpose
getPlayerSearchAvailability(options?)Checks the nearest target.
getTargetPlayerSearchAvailability(targetId, options?)Checks a specific target.
getPlayerSearchConfig()Returns a read-only snapshot of Config.PlayerSearch.
startPlayerSearch(context?)Starts the search UI for context.targetId or the nearest target.
local available = exports["sky_jobs_base"]:getTargetPlayerSearchAvailability(targetId)

if available then
    exports["sky_jobs_base"]:startPlayerSearch({
        targetId = targetId
    })
end

The target must be nearby and restrained. Inventory reads and every item transfer are validated again on the server.


Radial Menu

When Config.JobRadial.targetContext.enabled is enabled, the player target tracker and its marker remain active for the entire time the radial menu is open. This is independent of whether the currently visible actions require a player target.

openRadialMenu()

  • Purpose: Opens the job radial menu as if the player pressed the configured hotkey.
exports["sky_jobs_base"]:openRadialMenu()

registerRadialProvider(options)

  • Purpose: Registers the calling client resource as a dynamic radial action provider.
  • Arguments:
    • options.jobKeys (string | string[]?) - limits the provider to exact job keys.
    • options.jobGroups (string | string[]?) - limits the provider to job groups such as police or crime.
  • Returns: boolean.

The provider resource must expose getRadialActions, triggerRadialMenuAction, and optionally canInteractRadialMenuAction. Prefer this self-registration flow over adding the resource to Config.JobRadial.providers; the config list is intended for providers that cannot register themselves. A live self-registration and its job filters take precedence over a legacy config entry for the same resource.

An action may use menu = { id, icon?, label?, description? } to join a submenu. Actions with the same menu ID are grouped together, while a submenu containing only one currently available action is flattened automatically. Actions may also use oxTarget = { types, bones?, distance?, boneRadius?, netId? }, radialTarget = true, and targetValidate = true to receive and validate the live entity context.

When an action already displayed its own feedback or intentionally cancelled without a notification, its handler can return false, { silent = true }.

exports["sky_jobs_base"]:registerRadialProvider({
    jobGroups = { "crime" }
})

getRadialActions()

  • Purpose: Returns all available radial menu actions with their metadata.
  • Returns: RadialAction[] — array of action objects with id, label, icon, disabled, and more.
local actions = exports["sky_jobs_base"]:getRadialActions()

for _, action in ipairs(actions) do
    print(action.id, action.label, action.disabled)
end

getRadialAction(actionId)

  • Purpose: Fetches a single radial action by its ID.
  • Arguments:
    • actionId (string) — the action identifier.
  • Returns: table | nil — the action object, or nil if not found.
local action = exports["sky_jobs_base"]:getRadialAction("stretcher_carry")

isRadialMenuActionAvailable(actionId)

  • Purpose: Checks if a radial action exists and is currently enabled.
  • Arguments:
    • actionId (string)
  • Returns: booleantrue when the action exists and is not disabled.
if exports["sky_jobs_base"]:isRadialMenuActionAvailable("treat_patient") then
    -- Action is available
end

triggerRadialMenuAction(actionId, context?)

  • Purpose: Executes a radial action handler without opening the UI.
  • Arguments:
    • actionId (string)
    • context (table?) - optional selected entity, network ID, distance, and target information forwarded to the action provider.
  • Returns:
    • booleantrue on success, false on failure.
    • table? — on failure, a table with key (locale key) and fallback (error message).
local success, err = exports["sky_jobs_base"]:triggerRadialMenuAction("treat_patient")

if not success then
    print("Failed:", err.fallback)
end

Built-in Actions

These actions are registered by sky_jobs_base itself. Job scripts (like sky_ambulancejob) add their own actions on top.

Action IDDescription
tabletOpens the tablet interface.
remove_trunk_propRemoves a nearby placed trunk prop.

Dispatch

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

  • Purpose: Sends a dispatch alert to on-duty members of the specified jobs. Client-side wrapper that triggers the server event.
  • Arguments:
    • title (string) — dispatch title.
    • message (string) — dispatch description.
    • coords (vector3) — location of the incident.
    • jobs (string | string[]) — job name or array of job names to notify.
    • meta (table?) — optional metadata:
      • source (number?) — source player ID.
      • sourceId (string?) — additional source identifier.
      • category (string?) — dispatch category.
  • Returns: boolean — always true (server validates asynchronously).
exports["sky_jobs_base"]:createDispatch(
    "Traffic Accident",
    "Vehicle collision on Route 68",
    vector3(1234.0, -567.0, 30.0),
    { "ambulance", "police" },
    { category = "accident" }
)

Storage

getNearbyTrunkPropTarget(maxDistance)

  • Purpose: Finds the nearest managed trunk prop within the given distance.
  • Arguments:
    • maxDistance (number) — search radius in game units.
  • Returns: table | nil
    • distance (number) — distance to the prop.
    • label (string) — display label.
local target = exports["sky_jobs_base"]:getNearbyTrunkPropTarget(5.0)

if target then
    print(target.label, target.distance)
end

removeNearbyTrunkProp(maxDistance)

  • Purpose: Removes the nearest managed trunk prop.
  • Arguments:
    • maxDistance (number) — search radius.
  • Returns:
    • booleantrue on success.
    • string? — on failure, a locale key describing the error.
local success, errorKey = exports["sky_jobs_base"]:removeNearbyTrunkProp(5.0)

if not success then
    print("Failed:", errorKey)
end

startTrunkPropPlacement(prop, options)

  • Purpose: Starts the trunk prop placement flow for a configured prop. This can be used by external scripts that need the same preview / place / cancel behaviour as the built-in storage UI.
  • Arguments:
    • prop (table) - prop definition with name, model, optional label, and optional image.
    • options (table?) - optional placement settings:
      • placeCallback (string?) - server callback name that must return true or { success = true } before the prop is placed.
      • placeContext (table?) - payload passed to placeCallback.
      • stopAfterPlace (boolean?) - when true, placement mode closes after one successful placement.
  • Returns: boolean - true when placement mode started.
local started = exports["sky_jobs_base"]:startTrunkPropPlacement({
    name = "repair_crate",
    label = "Repair Crate",
    model = "prop_box_wood02a_pu"
}, {
    placeCallback = "my_resource:consumeRepairCrate",
    placeContext = { item = "repair_crate" },
    stopAfterPlace = true
})

External Garage Integration

These exports allow third-party garage systems to register their vehicles for trunk prop functionality. When a vehicle is spawned by an external garage, call registerExternalTrunkVehicle so the trunk interaction point is created and props can be used.

registerExternalTrunkVehicle(vehicle)

  • Purpose: Registers an externally-spawned vehicle for trunk and prop interactions. Adds the vehicle model to the allowed list and creates the trunk interaction point.
  • Arguments:
    • vehicle (number) — the vehicle entity handle.
  • Returns: booleantrue on success, false if the entity is invalid.
-- After your garage spawns the vehicle:
local vehicle = GetVehiclePedIsIn(PlayerPedId(), false)

local success = exports["sky_jobs_base"]:registerExternalTrunkVehicle(vehicle)

if success then
    print("Trunk props enabled for this vehicle")
end
The player must be on-duty for the correct job. The server-side export registerExternalVehicle must also be called for full trunk functionality (inventory, transfers).

unregisterExternalTrunkVehicle(vehicle)

  • Purpose: Removes the trunk interaction point for an externally-registered vehicle. Call this when the vehicle is despawned or parked.
  • Arguments:
    • vehicle (number) — the vehicle entity handle.
  • Returns: booleantrue on success, false if the entity or network ID is invalid.
exports["sky_jobs_base"]:unregisterExternalTrunkVehicle(vehicle)

Support

Need help? Our support team is always ready to assist

Join Discord