JG Docs
Vehicle Keys

Server API

giveKeys

Give a player a key for a plate or reuse their valid held key (GiveKeys is an alias).

-- source: number player server ID
-- plate: string
-- model: string spawn name or number model hash, optional
-- options: table, optional; pass nil for model when using options alone
local result = exports["jg-vehiclekeys"]:giveKeys(source, plate, model, options)

-- example: give an additional physical copy
local result = exports["jg-vehiclekeys"]:giveKeys(1, "ABC123", "adder", {
  duplicate = true,
  design = "karin",
})
if not result.success then
  print(result.code)
end

ParameterTypeRequiredDescription
options.duplicatebooleanNoIssue an additional physical copy instead of reusing a held key; defaults to false
options.designstringNoFob design; defaults to the vehicle's design
options.expiresAtnumberNoPhysical key expiry as a Unix timestamp in seconds; omitted means no expiry
options.collectionbooleanNoApply the configured garage collection key policy; defaults to false
options.guardfunctionNoReturn true while your server operation is still valid; returning false cancels delivery
ReturnsTypeDescription
result.successbooleanWhether access was supplied, reused or the vehicle was excluded
result.codestring?Error code when issuance fails
result.data.keyIdstring?Physical key serial when available
result.data.existingboolean?true when an existing key or grant was reused
result.data.virtualboolean?true when a virtual grant was issued
result.data.returnednumber?Number of stored physical copies returned
result.data.ignoredboolean?true when Vehicle Keys excludes this vehicle

The selected key setup, copy limits and inventory capacity still apply. Stored registered vehicles can be identified by plate without a live entity.

removeKeys

Remove a player's currently held keys for a plate (RemoveKeys is an alias).

-- source: number player server ID
-- plate: string
-- model: string spawn name or number model hash, optional
local result = exports["jg-vehiclekeys"]:removeKeys(source, plate, model)

-- example
local result = exports["jg-vehiclekeys"]:removeKeys(1, "ABC123", "adder")
if result.success then
  print(result.data.removed)
end

ReturnsTypeDescription
result.successbooleanWhether removal completed
result.codestring?Error code when removal fails
result.data.removednumber?Number of held physical copies or virtual grants removed
result.data.ignoredboolean?true when Vehicle Keys excludes this vehicle

Transferred and stashed copies keep their own validity.

hasKeys

Check whether a player holds a valid key for a plate or network ID (HasKeys is an alias).

-- source: number player server ID
-- plateOrNetId: string plate or number network ID
local hasKeys = exports["jg-vehiclekeys"]:hasKeys(source, plateOrNetId)

-- example
local hasKeys = exports["jg-vehiclekeys"]:hasKeys(1, "ABC123")
ReturnsTypeDescription
hasKeysbooleanWhether the player has a valid carried physical key or issued virtual grant

Owning the vehicle alone does not count as holding a key. A numeric second argument is a network ID; use hasKeysForEntity for an entity.

getKeys

Get a player's individual key copies and virtual grants (GetKeys is an alias).

-- source: number player server ID
local keys = exports["jg-vehiclekeys"]:getKeys(source)

-- example
for _, key in ipairs(exports["jg-vehiclekeys"]:getKeys(1)) do
  print(key.plate, key.valid)
end

ReturnsTypeDescription
keystable[]Individual key entries, or an empty array when unavailable
entry.keyIdstringKey serial or virtual grant reference
entry.vehicleIdstringVehicle reference used internally by Vehicle Keys
entry.platestringCurrent saved plate
entry.modelstring|numberVehicle model
entry.vehicleNamestringVehicle display name
entry.designstringFob design
entry.validbooleanWhether this key currently provides access
entry.expiresAtnumber?Expiry as a Unix timestamp in seconds
entry.sharedBystring?Sharer's citizenid (QBCore/Qbox) or identifier (ESX)
entry.fleetRuleIdstring?Fleet rule reference
entry.slotnumber?Physical inventory slot
entry.virtualboolean?true for virtual grants

Entries can include invalid keys. Check entry.valid before treating an entry as access. Multiple copies of the same vehicle key appear separately.

giveKeysToEntity

Give a player keys using the same entity arguments as Qbox's server GiveKeys.

-- source: number player server ID
-- vehicle: number server entity
-- skipNotification: boolean, optional; defaults to false
local given = exports["jg-vehiclekeys"]:giveKeysToEntity(source, vehicle, skipNotification)

-- example
local vehicle = GetVehiclePedIsIn(GetPlayerPed(1), false)
local given = exports["jg-vehiclekeys"]:giveKeysToEntity(1, vehicle, true)
ReturnsTypeDescription
giventrue|niltrue when a key or grant was delivered; nil when already held, excluded or unsuccessful

This reuses the normal key setup and does not create an extra copy for a player who already has one.

removeKeysFromEntity

Remove a player's held keys using the same entity arguments as Qbox's server RemoveKeys.

-- source: number player server ID
-- vehicle: number server entity
-- skipNotification: boolean, optional; defaults to false
local removed = exports["jg-vehiclekeys"]:removeKeysFromEntity(source, vehicle, skipNotification)

-- example
local vehicle = GetVehiclePedIsIn(GetPlayerPed(1), false)
local removed = exports["jg-vehiclekeys"]:removeKeysFromEntity(1, vehicle, true)
ReturnsTypeDescription
removedtrue|niltrue when at least one held copy or grant was removed; nil otherwise

hasKeysForEntity

Check whether a player holds a valid key using the same entity arguments as Qbox's server HasKeys.

-- source: number player server ID
-- vehicle: number server entity
local hasKeys = exports["jg-vehiclekeys"]:hasKeysForEntity(source, vehicle)

-- example
local vehicle = GetVehiclePedIsIn(GetPlayerPed(1), false)
local hasKeys = exports["jg-vehiclekeys"]:hasKeysForEntity(1, vehicle)
ReturnsTypeDescription
hasKeysbooleanWhether the player currently has a valid key or grant for the entity

isPlayerNearVehicle

Check whether a player is within the configured fob range of a server vehicle entity.

-- source: number player server ID
-- vehicle: number server entity
-- Uses the fob distance from the in-game admin settings; default: 20 metres.
local nearby = exports["jg-vehiclekeys"]:isPlayerNearVehicle(source, vehicle)

-- example
local vehicle = GetVehiclePedIsIn(GetPlayerPed(1), false)
local nearby = exports["jg-vehiclekeys"]:isPlayerNearVehicle(1, vehicle)
ReturnsTypeDescription
nearbybooleanWhether the player's distance is within the configured range

This checks distance only. Your script checks routing buckets and access where needed.

unlockVehicle

Open a live vehicle's door locks by plate (UnlockVehicle is an alias).

-- source: number player server ID your script is acting for
-- plate: string
-- model: string spawn name or number model hash, optional
local result = exports["jg-vehiclekeys"]:unlockVehicle(source, plate, model)

-- example
local result = exports["jg-vehiclekeys"]:unlockVehicle(1, "ABC123", "adder")

ReturnsTypeDescription
result.successbooleanWhether the door state was changed
result.codestring?Error code when the call fails
result.data.netIdnumber?Vehicle network ID
result.data.lockedboolean?false after a successful call

This is a server script action. The supplied player does not need a key or proximity to the vehicle.

setLockState

Set a live vehicle's door state using the same entity arguments as Qbox's server SetLockState.

-- vehicle: number server entity
-- state: string, "lock" or "unlock"
exports["jg-vehiclekeys"]:setLockState(vehicle, state)

-- example
local vehicle = GetVehiclePedIsIn(GetPlayerPed(1), false)
exports["jg-vehiclekeys"]:setLockState(vehicle, "lock")

No player key or proximity check is required.

canParkVehicle

Check whether the key policy permits a player to park a vehicle.

-- source: number player server ID
-- plate: string
-- kind: string, optional; "garage" (default) or "impound"
local allowed = exports["jg-vehiclekeys"]:canParkVehicle(source, plate, kind)

-- example
local allowed = exports["jg-vehiclekeys"]:canParkVehicle(1, "ABC123", "garage")
ReturnsTypeDescription
allowedbooleanWhether the configured key policy and pending-operation checks permit parking

Impounding does not require the officer to hold a key. Your garage script still checks storage permission, driver, distance and routing bucket.

canCollectVehicle

Check whether a player can receive a vehicle under the configured key collection policy.

-- source: number player server ID
-- plate: string
-- notify: boolean, optional; defaults to false
-- Set notify to true to show the no-keys-available message when appropriate.
local allowed, errorCode = exports["jg-vehiclekeys"]:canCollectVehicle(source, plate, notify)

-- example
local allowed, errorCode = exports["jg-vehiclekeys"]:canCollectVehicle(1, "ABC123", true)
ReturnsTypeDescription
allowedbooleanWhether held keys, stored keys and the configured collection policy permit collection
errorCodestring?Reason collection was refused

This checks availability without issuing a key. Your garage script still checks who may collect the vehicle.

vehicleParked

Apply the configured key storage policy after your script confirms that a vehicle was parked.

-- plate: string
-- operationId: string unique to this parking operation, maximum 90 characters
-- kind: string, "garage" or "impound"
-- parkerIdentifier: string citizenid (QBCore/Qbox) or identifier (ESX), not a server ID
local result = exports["jg-vehiclekeys"]:vehicleParked(plate, operationId, kind, parkerIdentifier)

-- example: save and reuse the same operation ID when retrying
local result = exports["jg-vehiclekeys"]:vehicleParked("ABC123", "garage-store:1842", "garage", "CHAR12345")

ReturnsTypeDescription
result.successbooleanWhether the parking key policy completed
result.codestring?Error code when finalisation needs retrying or the request is invalid
result.data.existingboolean?true when this parking operation already completed
result.data.ignoredboolean?true when Vehicle Keys excludes this vehicle

Keep the original plate, operation ID, kind and character identifier in your saved parking record. Retry the same arguments until finalisation succeeds, and block collection while it is pending. A completed retry does not affect keys issued later.

vehicleOwnershipChanged

Transfer the seller's carried keys after your script saves a legal ownership change (VehicleOwnershipChanged is an alias).

-- plate: string
-- ownerIdentifier: string new owner's citizenid (QBCore/Qbox) or identifier (ESX)
-- requestId: string unique to the sale or transfer, maximum 100 characters
-- previousOwner: string previous character identifier, optional for a new vehicle
-- recipientIdentifier: string key recipient, optional; defaults to ownerIdentifier
local result = exports["jg-vehiclekeys"]:vehicleOwnershipChanged(plate, ownerIdentifier, requestId, previousOwner, recipientIdentifier)

-- example
local result = exports["jg-vehiclekeys"]:vehicleOwnershipChanged("ABC123", "BUYER123", "sale:1842", "SELLER123")

ReturnsTypeDescription
result.successbooleanWhether a saved transfer receipt was accepted
result.codestring?Error code when the call fails
result.data.operationIdstring?Saved transfer receipt reference
result.data.pendingboolean?true while key delivery is still being recovered
result.data.transferrednumber?Number of copies or grants transferred so far
result.data.existingboolean?Whether valid access was already present
result.data.issuedboolean?Whether a missing key was issued under the ownership-transfer setting

Save the request ID with your sale and reuse the same arguments after an interruption. The saved owner must match ownerIdentifier. Use recipientIdentifier when a society owns the vehicle but a player receives its keys. Transferred, dropped and stashed keys retain their independent validity.

vehiclePlateChanged

Refresh key plate information after your script saves a vehicle's new plate.

-- plate: string current/new plate already saved in the framework vehicle table
-- previousPlate: string previous plate, optional
local result = exports["jg-vehiclekeys"]:vehiclePlateChanged(plate, previousPlate)

-- example
local result = exports["jg-vehiclekeys"]:vehiclePlateChanged("NEW123", "OLD123")

ReturnsTypeDescription
result.successbooleanWhether the vehicle was resolved and metadata refresh was requested
result.codestring?Error code when the call fails
result.data.platestring?Current plate read from the saved vehicle record

Key serials and access stay valid. Online loose items refresh through the inventory; stored or offline items refresh when their possession is next checked.

getVehicleSecurity

Get the security fitted to a vehicle by plate.

-- plate: string
-- model: string spawn name or number model hash, optional
local result = exports["jg-vehiclekeys"]:getVehicleSecurity(plate, model)

-- example
local result = exports["jg-vehiclekeys"]:getVehicleSecurity("ABC123", "adder")

ReturnsTypeDescription
result.successbooleanWhether the security state was read
result.codestring?Error code when the call fails
result.data.gpsboolean?Whether a GPS tracker is fitted
result.data.alarmTiernumber?Alarm tier from 1 to 3
result.data.immobiliserstring?"none", "immobiliser" or "ghost"
result.data.versionnumber?Security state revision
result.data.jammedUntilnumber?Jamming end time as a Unix timestamp in seconds, or 0
result.data.pinVersionnumber?Ghost PIN revision
result.data.pinTimeoutMsnumber?Configured PIN interaction timeout in milliseconds

The PIN and its stored hash are not returned.

getVehicleTrackingLocation

Get a vehicle's current GPS position and fitted security by plate.

-- source: number player server ID viewing the location
-- plate: string
-- model: string spawn name or number model hash, optional
local result = exports["jg-vehiclekeys"]:getVehicleTrackingLocation(source, plate, model)

-- example
local result = exports["jg-vehiclekeys"]:getVehicleTrackingLocation(1, "ABC123", "adder")
if result.success then
  print(result.data.coords.x, result.data.coords.y)
end

ReturnsTypeDescription
result.successbooleanWhether a live position is available
result.codestring?Error code, such as "securityGpsRequired" or "securityGpsJammed"
result.data.coordstable?Position containing x, y and z
result.data.platestring?Current saved plate
result.data.updatedAtnumber?Position time as a Unix timestamp in seconds
result.data.signalstring?"live" when a current position is returned
result.data.securitytable?Fitted gps, alarmTier and immobiliser values
result.data.trackingIntervalMsnumber?Suggested refresh interval in milliseconds
result.data.retryAfternumber?Seconds until jamming ends, when jammed
result.data.lockedboolean?Current lock state when available
result.data.engineOnboolean?Current engine state when available

A working GPS and a live vehicle are required. Your script checks routing buckets and who may view the location.

getVehicleGhostInstallations

Check multiple plates for fitted Ghost immobilisers in one call.

-- plates: array of strings, maximum 512 entries
local result = exports["jg-vehiclekeys"]:getVehicleGhostInstallations(plates)

-- example
local result = exports["jg-vehiclekeys"]:getVehicleGhostInstallations({ "ABC123", "DEF456" })
if result.success then
  print(result.data.vehicles["ABC123"])
end

ReturnsTypeDescription
result.successbooleanWhether the batch was checked
result.codestring?Error code when the call fails
result.data.vehiclestable?Normalised plate keys mapped to booleans; true means Ghost is fitted

Unknown plates return false. Duplicate registered rows for a plate cause "vehicleIdentityConflict".

changeVehiclePin

Set a fitted Ghost immobiliser's four-digit PIN from your server script.

-- source: number player server ID your script is acting for
-- plate: string
-- pin: string containing exactly four digits; use a string to preserve leading zeroes
local result = exports["jg-vehiclekeys"]:changeVehiclePin(source, plate, pin)

-- example
local result = exports["jg-vehiclekeys"]:changeVehiclePin(1, "ABC123", "0427")

ReturnsTypeDescription
result.successbooleanWhether the PIN was saved
result.codestring?Error code when the call fails
result.data.completeboolean?true when the change completed
result.data.platestring?Vehicle plate
result.data.versionnumber?Updated security revision
result.data.pinVersionnumber?Updated Ghost PIN revision

Your script checks permission and confirms the new PIN with the player before calling. An active security interaction or unfinished installation can refuse the change.

Last updated 1 November 2026

On this page