Nord Vehicle Keys
Official Nord Lab documentation for Nord Vehicle Keys. Covers installation, strict physical keys, vehicle locking, theft systems, stolen-key expiry, recovery NPCs, ghost placement, bridges, developer exports, database, security and troubleshooting.
- 1 · Getting Started
- 2 · Configuration
- 3 · Vehicle Keys & Locking
- 4 · Theft & Stolen Keys
- 5 · Recovery NPC & Placement
- 6 · Bridges & Compatibility
- Bridge Architecture
- Framework Bridge
- Inventory Bridge
- Notifications & Text UI
- Custom Ownership Bridge
- 7 · Developer API
- Server Key Exports
- Physical Key Item Exports
- Server Vehicle Exports
- Client Exports
- Garage Integration
- Dealership Integration
- Rental Integration
- 8 · Database, Security & Troubleshooting
1 · Getting Started
Install Nord Vehicle Keys, understand its core concepts and verify a clean first boot.
Overview
Nord Vehicle Keys is a server-authoritative vehicle access system for FiveM. It combines physical vehicle keys, vehicle locking, theft gameplay, temporary stolen keys, recovery NPCs and a modular bridge layer for frameworks, inventories and UI providers.
Main features
- Physical
vehicle_keyitems with plate metadata. - Server-authoritative lock state using entity state bags.
- Lock / unlock from keybind, commands or the physical-key remote.
- Permanent owner keys, shared keys, temporary keys and stolen/session keys.
- Carjacking of NPC drivers by aiming a valid firearm.
- Lockpick and hotwire flows with configurable difficulty and alarm chances.
- Stolen-key expiry when leaving the stolen vehicle plus a safety timeout.
- Persistent key-recovery NPCs for owned vehicles.
- In-game admin panel for recovery NPC management.
- Ghost NPC placement editor with movement, rotation, height and ground snapping.
- Framework, inventory, notification and Text UI bridges isolated from the core.
- Server exports for garages, dealerships, rentals and other trusted resources.
Design principle
Normal access is intentionally strict when physical keys are enabled:
If the player no longer has the matching physical key item, the resource does not silently recreate it during an access check.
A missing owner key must be deliberately reissued through the recovery NPC, an admin action or a trusted server export.
Requirements & Installation
Requirements
| Requirement | Status |
|---|---|
| FiveM server | Required |
| OneSync | Required for authoritative entity checks |
oxmysql |
Required when persistence/ownership tables are used |
| QBCore / QBX / ESX | Optional |
nord_inventory |
Recommended for native physical-key metadata |
ox_inventory |
Supported for generic item checks |
ox_lib |
Optional notification/Text UI provider |
Resource installation
- Copy the folder as
nord_vehiclekeysinto your resources directory. - Start the database resource first.
- Start your framework and inventory before Nord Vehicle Keys.
- Add the recovery admin ACE if staff will manage recovery NPCs.
- Ensure the resource.
ensure oxmysql
ensure qb-core # or qbx_core / es_extended when used
ensure nord_inventory # recommended for physical vehicle_key items
ensure nord_vehiclekeys
Recovery admin permission:
add_ace group.admin nord.vehiclekeys.admin allow
Database
Auto SQL is enabled by default. The resource creates and validates its own tables at startup.
For a manual install, import:
sql/install.sql
First Boot Checklist
After installation, verify these points before opening the server to players.
oxmysqlis started before Nord Vehicle Keys.- The selected framework bridge is detected correctly.
- The selected inventory bridge is available.
- OneSync is enabled.
- No SQL or Lua errors appear during resource startup.
- The
vehicle_keyitem is registered when Nord Inventory auto-registration is enabled. /vehiclekeysadminopens for an ACE-authorized admin.- Lock/unlock works on an owned test vehicle.
- Removing the physical owner key removes normal access when strict physical-key mode is enabled.
- Recovering that key through a recovery NPC reissues access correctly.
Recommended start order
ensure oxmysql
ensure your_framework
ensure nord_inventory
ensure nord_vehiclekeys
If you use another inventory, replace nord_inventory with that resource and configure the Inventory bridge accordingly.
Resource Structure
The resource is intentionally split so integrations can be changed without editing the core logic.
nord_vehiclekeys/
├─ config/
│ ├─ bridges.lua
│ └─ main.lua
├─ client/
│ ├─ bridge/
│ │ ├─ framework.lua
│ │ ├─ inventory.lua
│ │ ├─ notify.lua
│ │ ├─ textui.lua
│ │ └─ minigame.lua
│ ├─ main.lua
│ ├─ theft.lua
│ ├─ stolen.lua
│ ├─ placement.lua
│ └─ recovery.lua
├─ server/
│ ├─ bridge/
│ │ ├─ framework.lua
│ │ ├─ inventory.lua
│ │ ├─ notify.lua
│ │ ├─ textui.lua
│ │ ├─ ownership.lua
│ │ └─ nord_inventory_registration.lua
│ ├─ api.lua
│ ├─ main.lua
│ ├─ stolen.lua
│ ├─ recovery.lua
│ └─ storage.lua
├─ shared/
├─ locales/
├─ web/
└─ sql/
For normal compatibility work, edit the appropriate file under client/bridge/ or server/bridge/ instead of changing main.lua.
2 · Configuration
Configure key behaviour, vehicle state, sharing, recovery, theft systems and persistence.
Core Configuration
The primary configuration file is:
config/main.lua
Common options:
Config.Debug = false
Config.Locale = 'en'
Config.Keybinds = {
Lock = 'L',
Hotwire = 'H'
}
Distances are controlled separately:
Config.Distances = {
ToggleLock = 18.0,
Action = 7.0,
Share = 7.0,
Ensure = 35.0
}
Vehicle state
Config.VehicleState = {
OwnedVehiclesSpawnLocked = true,
NPCVehiclesSpawnLockedChance = 65,
NPCLocksPlayerOnly = true,
NPCKeysInsideChance = 15,
}
NPCLocksPlayerOnly keeps ambient NPC traffic usable by GTA AI while still enforcing the logical player-facing lock state.
Physical Keys
Physical-key behaviour is configured under Config.PhysicalKeys.
Config.PhysicalKeys = {
Enabled = true,
Item = 'vehicle_key',
SyncWithAccess = true,
ItemGrantsAccess = true,
RequirePhysicalItemForAccess = true,
OwnerAccessWithoutPhysicalItem = false,
StoredAccessWithoutPhysicalItem = false,
AllowClientOwnerClaim = false,
IssueForJobAccess = false,
}
Strict mode behaviour
With the default strict settings:
- A physical key is authoritative for normal owner/shared access.
- Deleting or losing the item removes that physical access.
- Ownership alone does not silently recreate a missing key.
- A client cannot claim an owner key simply because it is near an owned vehicle.
- Trusted server resources should intentionally call
GiveKeyswhen issuing a new key.
This prevents accidental unlimited key regeneration.
Remote Configuration
Using a physical vehicle_key can open the built-in vehicle remote.
Config.PhysicalKeys.Remote = {
Enabled = true,
Range = 25.0,
RefreshMs = 250,
AllowTrunk = true,
CloseOnAction = false,
TrunkDoors = {},
}
The remote supports:
- Lock
- Unlock
- Open/close supported trunk
- Live in-range status
- Plate display
The remote closes with ESC. Its NUI is transparent while closed and does not create a fullscreen dark overlay.
TrunkDoors can be used to explicitly map unusual/front-trunk vehicles to a door index.
Sharing & Job Access
Key sharing
Config.ShareKeys = {
Enabled = true,
AllowReshare = false,
DefaultDurationSeconds = 3600,
PersistTemporaryKeys = true,
}
Player commands:
/givekey [server id]
/revokekey [server id]
The player must use the current vehicle or a nearby vehicle within the configured share distance.
Job access
Job access is empty by default to avoid unintended fleet access.
Example:
Config.JobAccess.police = {
minGrade = 0,
requireDuty = true,
platePrefixes = { 'LSPD', 'POL' },
models = { 'police', 'police2', 'police3' }
}
Job access can stay virtual so shared fleet vehicles do not generate large numbers of physical key items.
Persistence & Ownership
Persistence
Config.Persistence = {
Enabled = true,
Resource = 'oxmysql',
AutoInstall = true,
QueryTimeoutMs = 10000,
StartupTimeoutMs = 60000,
RetryIntervalMs = 1000,
PersistPermanentSharedKeys = true,
PersistTemporaryKeys = true,
}
Ownership tables
Default ownership mappings:
Config.Ownership.QB = {
table = 'player_vehicles',
ownerColumn = 'citizenid',
plateColumn = 'plate',
vehicleColumn = 'vehicle',
}
Config.Ownership.ESX = {
table = 'owned_vehicles',
ownerColumn = 'owner',
plateColumn = 'plate',
vehicleColumn = 'vehicle',
}
QBX uses the same default player_vehicles layout as QB.
For a custom garage schema, either change the configured table/columns or enable custom ownership and implement the ownership bridge.
3 · Vehicle Keys & Locking
Understand key types, lock state and the built-in player commands.
Key Types
Nord Vehicle Keys uses different key types for different access lifecycles.
| Key type | Typical use | Persistence |
|---|---|---|
owner |
Player-owned vehicle | Permanent |
shared |
Shared access | Permanent or timed |
temporary |
Rentals/scripts | Timed |
session |
Stolen/NPC vehicle | Temporary session |
admin |
Administrative grant | Permanent until removed |
When a physical key item is issued, metadata includes at least:
{
plate = 'ABC123',
keyType = 'owner',
expiresAt = 0,
sessionToken = ''
}
Session keys use a session token that is validated server-side and cannot be reused by another player connection.
Locking Controls
Default lock controls:
L Toggle current/nearest vehicle lock
/vehiclelock Toggle current/nearest vehicle lock
/lockvehicle Lock current/nearest vehicle
/unlockvehicle Unlock current/nearest vehicle
The lock key is configurable through Config.Keybinds.Lock and FiveM key mappings.
Lock state is synchronized using server-controlled vehicle state bags. This allows all clients to apply the same logical lock state while the server remains authoritative for access validation.
Admin Key Commands
Administrative key commands require the ACE configured in Config.Security.AdminAce.
Default ACE:
add_ace group.admin nord.vehiclekeys.admin allow
Commands:
/adminkey [server id] [plate]
/adminkeyremove [server id] [plate]
/adminkey issues administrative access and synchronizes the matching physical key item when physical keys are active.
/adminkeyremove removes stored access and the matching physical key item.
4 · Theft & Stolen Keys
Configure and operate carjacking, lockpick, hotwire and stolen-key cleanup.
Carjacking
Carjacking can start automatically when a player holds aim on an NPC driver with an allowed firearm.
Config.Carjacking = {
Enabled = true,
AimHoldMs = 850,
DurationMs = 3200,
CooldownMs = 10000,
GiveKeysOnSuccess = true,
SuccessChance = 100,
AlarmChance = 35,
RequireWeapon = true,
}
The NPC/vehicle action is reserved and validated server-side. The finish step validates the reserved vehicle, plate, action token, timing and distance without depending on volatile NPC network ownership.
Blocked melee, utility and throwable weapons can be configured through Config.Carjacking.BlockedWeapons.
Lockpick
Lockpick configuration:
Config.Lockpick = {
Enabled = true,
Item = 'lockpick',
DurationMs = 6500,
Difficulty = 4,
BreakChanceOnFail = 35,
AlarmChanceOnFail = 70,
AlarmChanceOnSuccess = 15,
GiveKeysWhenKeysFoundInside = true,
}
The configured inventory bridge validates and removes the item when required.
Command:
/lockpick
Developer client export:
exports.nord_vehiclekeys:StartLockpick(vehicle)
Hotwire
Hotwire configuration:
Config.Hotwire = {
Enabled = true,
Item = nil,
DurationMs = 9000,
Difficulty = 6,
FailCooldownMs = 3500,
AlarmChanceOnFail = 65,
AlarmChanceOnSuccess = 20,
}
Set Item to an item name if a hotwire kit should be required. When nil, no item is required.
Command:
/nordkeys_hotwire
Developer client export:
exports.nord_vehiclekeys:StartHotwire(vehicle)
Stolen Key Lifecycle
Keys obtained through NPC theft, lockpick-found-keys or hotwire are temporary stolen/session keys.
Config.StolenKeys = {
RemoveOnVehicleExit = true,
MaxDurationSeconds = 900,
ExitGraceMs = 1200,
ServerCheckMs = 750,
}
Default behaviour:
- The stolen key is issued for the specific vehicle.
- The player can use the vehicle normally while the stolen key is valid.
- After the player enters the vehicle and later exits it, the stolen key is revoked.
- The physical
vehicle_keyitem for that stolen access is removed. - A safety timeout removes abandoned session keys even if the player never enters the vehicle.
Permanent owner/shared/admin keys are not removed by the stolen-key cleanup flow.
Blocked Vehicle Classes
The theft system can block GTA vehicle classes and models.
Default blocked classes:
Config.Theft.BlockedClasses = {
[14] = true, -- boats
[15] = true, -- helicopters
[16] = true, -- planes
[18] = true, -- emergency
[19] = true, -- military
[21] = true, -- trains
}
Specific models can also be blocked:
Config.Theft.BlockedModels = {
'rhino',
}
5 · Recovery NPC & Placement
Manage persistent recovery NPCs and use the ghost placement editor.
Recovery Service
The recovery NPC allows players to reissue a lost physical owner key for a vehicle the server confirms they own.
It does not grant keys for arbitrary plates.
Recovery flow:
- Player approaches a configured recovery NPC.
- The NPC UI requests the player's owned vehicles from the server.
- Ownership is read from the configured framework vehicle table/custom ownership bridge.
- Player selects a vehicle.
- Ownership is validated again server-side.
- A permanent owner key and physical
vehicle_keyitem are issued.
Configuration:
Config.Recovery = {
Enabled = true,
AdminCommand = 'vehiclekeysadmin',
AdminAce = 'nord.vehiclekeys.admin',
DefaultModel = 's_m_m_autoshop_01',
DefaultLabel = 'Vehicle Key Service',
DefaultScenario = 'WORLD_HUMAN_CLIPBOARD',
InteractDistance = 2.2,
StreamDistance = 90.0,
Fee = 0,
}
Recovery Admin Panel
Open the recovery NPC admin panel with:
/vehiclekeysadmin
Required ACE:
add_ace group.admin nord.vehiclekeys.admin allow
The panel is in-game only and can be used to:
- Create recovery NPCs.
- Edit label/model/scenario.
- Move an existing NPC.
- Enter the visual placement editor.
- Delete recovery NPCs.
Recovery NPCs are persisted in the database and respawn after resource/server restarts.
Ghost Placement Editor
Creating or editing a recovery NPC can open the visual placement editor.
The preview NPC is transparent, non-colliding and frozen while being positioned.
Controls
| Control | Action |
|---|---|
W A S D |
Move relative to camera |
| Left mouse | Drag ghost toward the point under the cursor/raycast |
| Arrow Up / Down | Raise / lower |
| Arrow Left / Right | Rotate |
Q / E |
Rotate |
SHIFT |
Fast movement/rotation |
CTRL |
Precision movement |
G |
Snap to ground |
F |
Move to raycast point |
R |
Face camera direction |
ENTER |
Confirm and save |
ESC / BACKSPACE |
Cancel |
Placement configuration:
Config.Recovery.Placement = {
Enabled = true,
GhostAlpha = 145,
StartDistance = 2.0,
MoveStep = 0.035,
VerticalStep = 0.025,
RotateStep = 1.0,
FastMultiplier = 4.0,
PrecisionMultiplier = 0.25,
RaycastDistance = 25.0,
MaxDistanceFromAdmin = 35.0,
SnapToGroundOnStart = true,
DrawMarker = true,
}
The saved X/Y/Z/heading from the ghost is authoritative for the final NPC. The final spawn does not perform a second destructive ground snap.
6 · Bridges & Compatibility
Keep custom integrations isolated from the core by using the bridge layer.
Bridge Architecture
Bridge selection lives in:
config/bridges.lua
Config.Bridges = {
Framework = 'auto', -- auto | qb | qbx | esx | standalone | custom
Inventory = 'auto', -- auto | nord | ox | qb | esx | custom
Notify = 'auto', -- auto | ox | qb | esx | gta | custom
TextUI = 'auto', -- auto | ox | gta | custom
}
For a custom resource:
- Set the relevant bridge to
custom. - Edit only the matching bridge file.
- Return the values expected by the bridge contract.
- Leave the core resource logic unchanged.
This keeps updates easier because custom integrations stay isolated.
Framework Bridge
Framework bridge files:
client/bridge/framework.lua
server/bridge/framework.lua
Auto-detection order:
qbx_coreqb-corees_extended- standalone fallback
The server bridge provides:
- Framework detection.
- Player lookup.
- Stable identifier lookup.
- Job lookup.
- Grade normalization.
- Duty state handling.
Custom integration hooks:
NVKServerBridge.CustomGetPlayer(source)
NVKServerBridge.CustomGetIdentifier(source)
NVKServerBridge.CustomGetJob(source)
NVKClientBridge.CustomGetJob()
Return your framework's normal player/job objects in those hooks.
Inventory Bridge
Inventory bridge files:
client/bridge/inventory.lua
server/bridge/inventory.lua
Generic item checks support:
- Nord Inventory
- ox_inventory
- QB/QBX inventory through the framework player object
- ESX inventory
- Custom implementation
Native physical vehicle keys
The full physical vehicle_key metadata flow is native to nord_inventory.
Custom inventory hooks are provided for complete physical-key support:
NVKInventory.CustomHasItem(source, item, count)
NVKInventory.CustomRemoveItem(source, item, count)
NVKInventory.CustomHasVehicleKeyItem(source, plate)
NVKInventory.CustomResolveVehicleKeyMetadata(source, slot)
NVKInventory.CustomGiveVehicleKeyItem(source, plate, keyType, expiresAt, sessionBound)
NVKInventory.CustomRemoveVehicleKeyItem(source, plate)
NVKInventory.CustomCleanupInvalidVehicleKeyItems(source)
Client custom count hook:
NVKClientInventory.CustomGetItemCount(item, metadata)
If you use a custom inventory with strict physical keys, implement the physical-key hooks rather than modifying the core.
Notifications & Text UI
Notification and Text UI are independent bridges.
Files:
client/bridge/notify.lua
server/bridge/notify.lua
client/bridge/textui.lua
server/bridge/textui.lua
Supported notification modes:
auto | ox | qb | esx | gta | custom
Supported Text UI modes:
auto | ox | gta | custom
Custom notification hook:
function NVKNotify.Custom(message, kind, duration, title)
-- show your notification
return true
end
Custom Text UI hooks:
function NVKTextUI.CustomShow(id, text, options)
-- show your UI
return true
end
function NVKTextUI.CustomHide(id)
-- hide your UI
return true
end
The recovery interaction uses this bridge instead of hardcoded GTA help text.
Custom Ownership Bridge
Ownership is isolated in:
server/bridge/ownership.lua
For custom ownership logic:
Config.Ownership.Custom = true
Implement:
function NVKOwnership.CustomGetOwnerIdentifier(plate)
-- Return the framework identifier that owns this plate.
end
For the recovery UI, you can also implement:
function NVKOwnership.CustomGetOwnedVehicles(source, identifier)
return {
{ plate = 'ABC123', model = 'sultan' },
{ plate = 'XYZ987', model = 'adder' },
}
end
Trusted standalone/garage resources can set a runtime owner through the SetVehicleOwner server export.
7 · Developer API
Integrate garages, dealerships, rentals and other server resources through stable exports.
Server Key Exports
Key creation and removal should be performed from trusted server-side resources.
Recommended simple API
-- Permanent owner key + physical key item.
exports.nord_vehiclekeys:GiveKeys(source, plate)
-- Remove access/key for the plate.
exports.nord_vehiclekeys:RemoveKeys(source, plate)
-- Check access.
local hasKey, keyType, expiresAt = exports.nord_vehiclekeys:HasKeys(source, plate)
Aliases:
exports.nord_vehiclekeys:AddKey(source, plate)
exports.nord_vehiclekeys:DeleteKey(source, plate)
exports.nord_vehiclekeys:GiveOwnerKey(source, plate)
exports.nord_vehiclekeys:GiveSharedKey(source, plate, 0) -- permanent shared
exports.nord_vehiclekeys:GiveSharedKey(source, plate, 3600) -- timed shared
exports.nord_vehiclekeys:GiveTempKey(source, plate, 900) -- temporary
Advanced API:
exports.nord_vehiclekeys:GiveKey(source, plate, 'owner', 0)
exports.nord_vehiclekeys:GiveKey(source, plate, 'shared', 3600)
exports.nord_vehiclekeys:GiveTemporaryKey(source, plate, 900)
exports.nord_vehiclekeys:RemoveKey(source, plate)
exports.nord_vehiclekeys:HasKey(source, plate)
Physical Key Item Exports
These exports work directly with the physical key item layer.
exports.nord_vehiclekeys:GivePhysicalKeyItem(source, plate, 'owner', 0)
exports.nord_vehiclekeys:RemovePhysicalKeyItem(source, plate)
exports.nord_vehiclekeys:HasPhysicalKeyItem(source, plate)
Normally, use GiveKeys / RemoveKeys instead because they keep permission state and the physical item synchronized.
Use the physical-item exports only when you deliberately need low-level control.
Server Vehicle Exports
Vehicle state exports operate on a network ID.
exports.nord_vehiclekeys:SetLockState(netId, true)
exports.nord_vehiclekeys:GetLockState(netId)
exports.nord_vehiclekeys:ToggleLock(netId)
exports.nord_vehiclekeys:LockVehicle(netId)
exports.nord_vehiclekeys:UnlockVehicle(netId)
exports.nord_vehiclekeys:RegisterOwnedVehicle(netId)
exports.nord_vehiclekeys:SetVehicleOwner(netId, identifier)
RegisterOwnedVehicle is useful after spawning a framework-owned vehicle so the resource can initialize its authoritative state.
SetVehicleOwner creates a runtime ownership override for trusted custom/standalone integrations.
Client Exports
Client exports are useful for UI, vehicle interactions and custom gameplay.
local hasKey = exports.nord_vehiclekeys:HasKey(vehicleOrPlate)
local hasLocal = exports.nord_vehiclekeys:HasLocalKey(vehicleOrPlate)
exports.nord_vehiclekeys:ToggleLock(vehicle)
exports.nord_vehiclekeys:LockVehicle(vehicle)
exports.nord_vehiclekeys:UnlockVehicle(vehicle)
local vehicle, distance = exports.nord_vehiclekeys:GetClosestVehicle(10.0)
exports.nord_vehiclekeys:OpenKeyRemote(slot)
The theft module also exposes:
exports.nord_vehiclekeys:StartLockpick(vehicle)
exports.nord_vehiclekeys:StartHotwire(vehicle)
exports.nord_vehiclekeys:StartCarjack(vehicle, driver)
Physical item-use handlers are also exposed internally for inventory integration, but normal external resources should use the higher-level key exports.
Garage Integration
A garage that spawns a player's owned vehicle should register the entity and only issue a key when the garage intentionally wants to hand one to the player.
Server example:
local netId = NetworkGetNetworkIdFromEntity(vehicle)
exports.nord_vehiclekeys:RegisterOwnedVehicle(netId)
exports.nord_vehiclekeys:GiveKeys(source, plate)
If the garage stores the vehicle and should remove the currently issued key:
exports.nord_vehiclekeys:RemoveKeys(source, plate)
Do not create an insecure client event that accepts an arbitrary source and plate and forwards them directly to GiveKeys.
Dealership Integration
When a player purchases a vehicle, issue the key after the purchase and ownership transaction succeeds.
-- purchase validated, money removed and ownership row saved first
exports.nord_vehiclekeys:GiveKeys(source, plate)
When a dealership sells/transfers/removes a vehicle from a player, remove the old holder's key deliberately:
exports.nord_vehiclekeys:RemoveKeys(oldOwnerSource, plate)
If the new owner is online:
exports.nord_vehiclekeys:GiveKeys(newOwnerSource, plate)
This keeps physical key ownership explicit and avoids silent regeneration.
Rental Integration
Rental scripts should normally use temporary keys.
Example 30-minute rental:
exports.nord_vehiclekeys:GiveTempKey(source, plate, 1800)
When the rental ends early:
exports.nord_vehiclekeys:RemoveKeys(source, plate)
exports.nord_vehiclekeys:GiveSharedKey(source, plate, 3600)
Choose temporary for a short-lived one-player rental and shared when the semantics are intentionally shared access.
8 · Database, Security & Troubleshooting
Operate the resource safely in production and resolve the most common installation issues.
Database Schema
Auto SQL creates the resource schema automatically when persistence is enabled.
Core tables:
nord_vehiclekeys_keys
Stores persisted key grants:
- plate
- holder identifier
- key type
- expiry timestamp
- created/updated timestamps
nord_vehiclekeys_recovery_npcs
Stores persistent recovery NPC placement and appearance:
- label
- ped model
- scenario
- X/Y/Z
- heading
- creator identifier
nord_vehiclekeys_schema
Tracks internal database schema revisions. This is a database schema number, not the resource release number.
Manual SQL is included at:
sql/install.sql
Security Model
Nord Vehicle Keys is designed around server authority.
Important protections
- OneSync entity checks are required by default.
- Lock state is synchronized through entity state bags.
- Key grants/removals are validated server-side.
- Physical key metadata is re-read from the authoritative inventory slot.
- Session/stolen keys are bound to the player connection/session token.
- Carjacking actions use server-side action reservation and validation.
- Ownership lookup is server-side.
- Recovery keys are only issued after ownership validation.
- Admin actions use ACE permission checks.
- Sensitive compatibility events are disabled by default.
- Callback/action rate limits reduce spam and replay abuse.
Trusted export rule
Exports such as GiveKeys should only be called by trusted server resources after that resource has validated its own business logic.
Production Checklist
Before production deployment:
- OneSync enabled.
- Database backups available.
-
oxmysqlstarts before Nord Vehicle Keys. - Framework bridge detected correctly.
- Inventory bridge selected correctly.
-
vehicle_keydefinition is non-stackable when using Nord Inventory. - Recovery ACE configured only for staff who need it.
- Ownership table/columns match your framework schema.
- Custom bridge code returns valid values and does not trust arbitrary client payloads.
- Test owner key issue/removal.
- Test player key sharing and revocation.
- Test stolen key removal after exiting the vehicle.
- Test recovery NPC key reissue.
- Test ghost placement cancel/confirm.
- Test lock state with multiple players nearby.
Common Issues
Physical key exists but does not open the remote
Check that:
nord_inventorystarts beforenord_vehiclekeys.- The
vehicle_keyitem is non-stackable. - The slot metadata contains a normalized plate.
- The key is not expired.
- The physical-key item use handler is registered.
Player keeps getting a key back after deleting it
Strict physical-key mode should use:
RequirePhysicalItemForAccess = true
OwnerAccessWithoutPhysicalItem = false
StoredAccessWithoutPhysicalItem = false
AllowClientOwnerClaim = false
A missing key should then only return through recovery/admin/trusted server exports.
Recovery NPC is underground
Use the visual placement editor and save the final position. The saved Z is authoritative and the final NPC should not run a second ground snap.
Recovery NPC is stuck in a broken scenario pose
Use a valid GTA scenario name. The resource applies the scenario without a destructive intro sequence and freezes the NPC after the final placement is applied.
Fullscreen dark NUI overlay
The key remote NUI should be transparent and hidden while closed. If you replaced the web files, ensure html and body do not force a dark background or color-scheme: dark.
"The action is no longer valid" during carjacking
Make sure all resource files are from the same build and that OneSync is enabled. The carjack completion validates the reserved vehicle/action rather than relying on the NPC remaining in the same network seat state.
Bridge Troubleshooting
Framework not detected
Force the bridge in config/bridges.lua:
Config.Bridges.Framework = 'qb' -- or qbx / esx / standalone / custom
Inventory not detected
Force the bridge:
Config.Bridges.Inventory = 'nord' -- or ox / qb / esx / custom
If Config.Inventory.Strict = true, item-requiring actions are denied when no bridge can validate the item.
Custom notification not showing
Set:
Config.Bridges.Notify = 'custom'
and make NVKNotify.Custom(...) return true after showing the notification.
Custom Text UI not hiding
Both custom hooks must be implemented:
NVKTextUI.CustomShow(...)
NVKTextUI.CustomHide(...)
Return true when the action was handled.
FAQ
Does owning a vehicle automatically recreate a deleted key?
No, not with the default strict physical-key settings. The player must recover or be explicitly issued a new key.
Can I use the resource without Nord Inventory?
Yes for generic access/item checks through supported bridges. The complete physical vehicle_key metadata workflow is native to Nord Inventory; a custom inventory can implement the provided physical-key hooks.
Can a player recover a key for a vehicle they do not own?
No. Recovery validates ownership server-side before issuing the key.
Do stolen keys stay forever?
No. They are designed to expire when the player leaves the stolen vehicle and also have a safety timeout.
Can a garage or dealership give keys?
Yes. Use the trusted server export:
exports.nord_vehiclekeys:GiveKeys(source, plate)
Can I replace notifications or Text UI without editing the core?
Yes. Select custom in config/bridges.lua and edit only the matching bridge file.
Is the recovery NPC placement persistent?
Yes. NPC definitions and coordinates are stored in the database.