Browse docs
Client Exports
Player Interactions
The client exports below open or execute the shared handcuff, ziptie, leg-restraint, escort, vehicle, head-bag, and player-search flows.
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, orcut_ziptie.options.targetId(number?) - server ID of a specific target. The nearest player is used when omitted.options.displayOnly(boolean?) - usetruewhile 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 withoutdisplayOnly; 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) -cuffsorzipties.- Returns
boolean, string?- whether the request started and an optional failure reason.
exports["sky_jobs_base"]:requestCuff("zipties", {
targetId = targetId
})
Nearest-player cuff exports
| Export | Purpose |
|---|---|
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
| Export | Purpose |
|---|---|
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, ortake_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
| Export | Purpose |
|---|---|
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
| Export | Purpose |
|---|---|
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.
Player search
| Export | Purpose |
|---|---|
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 aspoliceorcrime.
- 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 withid,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, ornilif 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:
boolean—truewhen 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:
boolean—trueon success,falseon failure.table?— on failure, a table withkey(locale key) andfallback(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 ID | Description |
|---|---|
tablet | Opens the tablet interface. |
remove_trunk_prop | Removes 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— alwaystrue(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 | nildistance(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:
boolean—trueon 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 withname,model, optionallabel, and optionalimage.options(table?) - optional placement settings:placeCallback(string?) - server callback name that must returntrueor{ success = true }before the prop is placed.placeContext(table?) - payload passed toplaceCallback.stopAfterPlace(boolean?) - whentrue, placement mode closes after one successful placement.
- Returns:
boolean-truewhen 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:
boolean—trueon success,falseif 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
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:
boolean—trueon success,falseif 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