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)
endreturn {
success = true,
data = {
keyId = "8bc157d2-99ee-4a1b-b9fa-3bf3b811c602",
vehicleId = "42",
},
}| Parameter | Type | Required | Description |
|---|---|---|---|
options.duplicate | boolean | No | Issue an additional physical copy instead of reusing a held key; defaults to false |
options.design | string | No | Fob design; defaults to the vehicle's design |
options.expiresAt | number | No | Physical key expiry as a Unix timestamp in seconds; omitted means no expiry |
options.collection | boolean | No | Apply the configured garage collection key policy; defaults to false |
options.guard | function | No | Return true while your server operation is still valid; returning false cancels delivery |
| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether access was supplied, reused or the vehicle was excluded |
result.code | string? | Error code when issuance fails |
result.data.keyId | string? | Physical key serial when available |
result.data.existing | boolean? | true when an existing key or grant was reused |
result.data.virtual | boolean? | true when a virtual grant was issued |
result.data.returned | number? | Number of stored physical copies returned |
result.data.ignored | boolean? | 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)
endreturn {
success = true,
data = {
removed = 1,
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether removal completed |
result.code | string? | Error code when removal fails |
result.data.removed | number? | Number of held physical copies or virtual grants removed |
result.data.ignored | boolean? | 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")| Returns | Type | Description |
|---|---|---|
hasKeys | boolean | Whether 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)
endreturn {
{
keyId = "8bc157d2-99ee-4a1b-b9fa-3bf3b811c602",
vehicleId = "42",
plate = "ABC123",
model = "3078201489",
vehicleName = "Adder",
design = "karin",
valid = true,
slot = 3,
},
}| Returns | Type | Description |
|---|---|---|
keys | table[] | Individual key entries, or an empty array when unavailable |
entry.keyId | string | Key serial or virtual grant reference |
entry.vehicleId | string | Vehicle reference used internally by Vehicle Keys |
entry.plate | string | Current saved plate |
entry.model | string|number | Vehicle model |
entry.vehicleName | string | Vehicle display name |
entry.design | string | Fob design |
entry.valid | boolean | Whether this key currently provides access |
entry.expiresAt | number? | Expiry as a Unix timestamp in seconds |
entry.sharedBy | string? | Sharer's citizenid (QBCore/Qbox) or identifier (ESX) |
entry.fleetRuleId | string? | Fleet rule reference |
entry.slot | number? | Physical inventory slot |
entry.virtual | boolean? | 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)| Returns | Type | Description |
|---|---|---|
given | true|nil | true 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)| Returns | Type | Description |
|---|---|---|
removed | true|nil | true 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)| Returns | Type | Description |
|---|---|---|
hasKeys | boolean | Whether 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)| Returns | Type | Description |
|---|---|---|
nearby | boolean | Whether 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")return {
success = true,
data = {
netId = 312,
locked = false,
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether the door state was changed |
result.code | string? | Error code when the call fails |
result.data.netId | number? | Vehicle network ID |
result.data.locked | boolean? | 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")| Returns | Type | Description |
|---|---|---|
allowed | boolean | Whether 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)| Returns | Type | Description |
|---|---|---|
allowed | boolean | Whether held keys, stored keys and the configured collection policy permit collection |
errorCode | string? | 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")return {
success = true,
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether the parking key policy completed |
result.code | string? | Error code when finalisation needs retrying or the request is invalid |
result.data.existing | boolean? | true when this parking operation already completed |
result.data.ignored | boolean? | 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")return {
success = true,
data = {
operationId = "ownership:8e547e704519a20959b7a8d752eb963010bcd28b757b4a9dd74a67f09ad23e1c",
vehicleId = "42",
pending = false,
transferred = 1,
existing = false,
issued = false,
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether a saved transfer receipt was accepted |
result.code | string? | Error code when the call fails |
result.data.operationId | string? | Saved transfer receipt reference |
result.data.pending | boolean? | true while key delivery is still being recovered |
result.data.transferred | number? | Number of copies or grants transferred so far |
result.data.existing | boolean? | Whether valid access was already present |
result.data.issued | boolean? | 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")return {
success = true,
data = {
vehicleId = "42",
plate = "NEW123",
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether the vehicle was resolved and metadata refresh was requested |
result.code | string? | Error code when the call fails |
result.data.plate | string? | 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")return {
success = true,
data = {
gps = true,
alarmTier = 2,
immobiliser = "ghost",
version = 3,
jammedUntil = 0,
pinVersion = 1,
pinTimeoutMs = 60000,
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether the security state was read |
result.code | string? | Error code when the call fails |
result.data.gps | boolean? | Whether a GPS tracker is fitted |
result.data.alarmTier | number? | Alarm tier from 1 to 3 |
result.data.immobiliser | string? | "none", "immobiliser" or "ghost" |
result.data.version | number? | Security state revision |
result.data.jammedUntil | number? | Jamming end time as a Unix timestamp in seconds, or 0 |
result.data.pinVersion | number? | Ghost PIN revision |
result.data.pinTimeoutMs | number? | 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)
endreturn {
success = true,
data = {
security = {
gps = true,
alarmTier = 2,
immobiliser = "ghost",
},
trackingIntervalMs = 5000,
coords = { x = 215.76, y = -810.12, z = 30.73 },
vehicleId = "42",
plate = "ABC123",
updatedAt = 1793448000,
signal = "live",
locked = true,
engineOn = false,
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether a live position is available |
result.code | string? | Error code, such as "securityGpsRequired" or "securityGpsJammed" |
result.data.coords | table? | Position containing x, y and z |
result.data.plate | string? | Current saved plate |
result.data.updatedAt | number? | Position time as a Unix timestamp in seconds |
result.data.signal | string? | "live" when a current position is returned |
result.data.security | table? | Fitted gps, alarmTier and immobiliser values |
result.data.trackingIntervalMs | number? | Suggested refresh interval in milliseconds |
result.data.retryAfter | number? | Seconds until jamming ends, when jammed |
result.data.locked | boolean? | Current lock state when available |
result.data.engineOn | boolean? | 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"])
endreturn {
success = true,
data = {
vehicles = {
ABC123 = true,
DEF456 = false,
},
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether the batch was checked |
result.code | string? | Error code when the call fails |
result.data.vehicles | table? | 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")return {
success = true,
data = {
complete = true,
plate = "ABC123",
version = 4,
pinVersion = 2,
},
}| Returns | Type | Description |
|---|---|---|
result.success | boolean | Whether the PIN was saved |
result.code | string? | Error code when the call fails |
result.data.complete | boolean? | true when the change completed |
result.data.plate | string? | Vehicle plate |
result.data.version | number? | Updated security revision |
result.data.pinVersion | number? | 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