Pepper Keys
Vehicle keys as real items with ox_inventory – whoever holds the key drives the car. With locksmith, lock changes and hotwiring.
Overview
Pepper Keys turns the vehicle key into a real item. Whoever has the key in their inventory unlocks the car and starts the engine, even if they stole it. The owner without a key gets nowhere. Stolen? Change the lock at the locksmith and all old keys are worthless. Without a key, only hotwiring is left, with a minigame, a tool and an alarm.
Only player vehicles are locked. Vehicles from job scripts stay free to drive, you do not need to change anything there.
- Key as an ox_inventory item with plate and vehicle name
- Changing the lock makes old keys worthless, spare keys at the locksmith
- Hotwiring with minigame, tool, alarm and difficulty per vehicle class
- Works with any garage script that uses the framework vehicle table
- Staff command
/pkeys, four server exports and an alarm event for your dispatch script
Requirements
| Dependency | Required/optional | Used for | Link |
|---|---|---|---|
| FiveM server build 7290 or newer | required | Per fxmanifest.lua (/server:7290) |
https://runtime.fivem.net/artifacts/fivem/ |
| OneSync | required | Vehicles and state bags on the server | https://docs.fivem.net/docs/scripting-reference/onesync/ |
| ESX Legacy, QBCore or Qbox | required | Owner, money, police jobs (auto-detected) | https://github.com/esx-framework/esx_core · https://github.com/qbcore-framework/qb-core · https://github.com/Qbox-project/qbx_core |
| ox_inventory | required | The key is an ox_inventory item | https://github.com/overextended/ox_inventory |
| ox_lib | required | Helpers, key mapping | https://github.com/overextended/ox_lib |
| oxmysql | required | Table pepper_keys_locks |
https://github.com/overextended/oxmysql |
| Garage script | optional | Taking cars out and parking, as long as it uses the framework vehicle table | – |
| Dispatch script | optional | Report the car alarm to dispatch (bridge/server/dispatch.lua) |
– |
Without a framework or without a running ox_inventory, Pepper Keys stays inactive and says so in the server console.
Installation
Copy the folder to
resources/[pepper]/pepper_keys.Do not rename the folder. Other scripts call
exports.pepper_keys, which only works with the namepepper_keys.Add the entry from
install/items/ox_inventory.txttoox_inventory/data/items.lua.Copy
install/images/pepper_carkey.pngtoox_inventory/web/images.In your
server.cfg, after your framework,oxmysql,ox_libandox_inventory:
ensure oxmysql
ensure ox_lib
ensure es_extended # or qb-core / qbx_core
ensure ox_inventory
ensure pepper_keys
add_ace group.admin pepper.keys.admin allow
- Start the server. The console shows "Pepper Keys 1.0.0 started (esx)" (or your framework).
Database: The script creates the table pepper_keys_locks on start (server/db.lua). You only need install/pepper_keys.sql
(same content) if your database user is not allowed to create tables. Then import it once with HeidiSQL or phpMyAdmin.
Items per inventory:
| Inventory | Item | File | Image |
|---|---|---|---|
| ox_inventory | pepper_carkey (weight 50, not stackable) |
install/items/ox_inventory.txt → ox_inventory/data/items.lua |
install/images/pepper_carkey.png → ox_inventory/web/images |
Other inventories are not supported. The item entry ships with a German label. On an English server, change label and
description in items.lua.
First test
- As an admin, type
/pkeys give <plate>for one of your vehicles. The key is now in your inventory. - Press U at the vehicle: it locks or unlocks with a light signal.
- Get in: with the key the engine starts. Drop the key, get out and back in: the engine stays off.
- Without a key and with a
lockpickin your inventory, press K and play the minigame. - Drive to the locksmith (default at
-205.5, -1313.3) and get a spare key with E.
Configuration
| File | Controls |
|---|---|
config/config.lua |
Language, framework, admin groups, item, keys, range, accounts, hotwiring, locksmith |
config/server.lua |
Admin ACE, Discord webhook for staff actions (never sent to clients) |
locales/de.json, locales/en.json |
All in-game texts |
bridge/server/dispatch.lua |
Integration with your dispatch script |
Basics
Config.Locale = 'de'
Config.Framework = 'auto'
Config.Item = 'pepper_carkey'
Config.Range = 15.0
Config.PayAccounts = { 'bank', 'money' }
| Option | Default | Description |
|---|---|---|
Config.Locale |
'de' |
'de' or 'en' |
Config.Framework |
'auto' |
auto, esx, qbcore, qbox |
Config.Debug |
false |
Extra console output |
Config.AdminGroups |
{ 'admin', 'superadmin', 'god' } |
Framework groups with admin rights (in addition to the ACE) |
Config.AdminCommand |
'pkeys' |
Name of the staff command |
Config.Item |
'pepper_carkey' |
Item name of the key |
Config.Range |
15.0 |
Lock range in metres |
Config.LockKey / HotwireKey / InteractKey |
U / K / E |
Default keys |
Config.PayAccounts |
{ 'bank', 'money' } |
Order of accounts when paying |
Hotwiring
Config.Hotwire = {
Enabled = true,
Item = 'lockpick',
ItemBreakChance = 40,
AlarmChance = 70,
Cooldown = 30,
MinPolice = 0,
PoliceJobs = { 'police', 'sheriff' },
}
| Option | Default | Description |
|---|---|---|
Enabled |
true |
Hotwiring on/off |
Item |
'lockpick' |
Tool, false = none needed |
ItemBreakChance |
40 |
Percent chance the tool breaks on failure |
AlarmChance |
70 |
Percent chance of the car alarm |
Cooldown |
30 |
Seconds to wait after a failed attempt |
MinPolice |
0 |
This many people from PoliceJobs must be on duty |
Range |
3.0 |
Distance to the vehicle |
AlarmSeconds |
30 |
Siren duration |
Levels |
easy 3/22, medium 4/16, hard 5/11 | Hits (rounds) and hit zone size in percent (width) |
Classes |
classes 2–5 medium, 6–7 hard | GTA vehicle class → level, otherwise easy |
Locksmith
Config.Locksmith = {
CopyFee = 500,
LockFee = 2500,
FirstFree = true,
Places = {
{ label = 'Schlüsseldienst', coords = vec3(-205.5, -1313.3, 31.3), radius = 3.0, blip = true },
},
}
| Option | Default | Description |
|---|---|---|
CopyFee |
500 |
Spare key |
LockFee |
2500 |
Lock change including a new key |
FirstFree |
true |
First key for existing vehicles is free |
Places |
1 place | Places with label, coordinates, radius and blip |
Server
| Option | Default | Description |
|---|---|---|
ServerConfig.AdminAce |
'pepper.keys.admin' |
ACE for the staff command |
ServerConfig.Webhook |
'' |
Discord webhook for staff actions ('' = off) |
ServerConfig.WebhookName |
'Pepper Keys' |
Sender name in the webhook |
How it works
| Input | Purpose |
|---|---|
| U | Lock or unlock the nearest vehicle (range Config.Range) |
| K | Hotwire, from the driver seat or at the door |
| E | Open the locksmith |
- Getting in: As the driver, the script asks the server once. With a matching key the engine starts, otherwise it stays off.
- Handing over a key: Just give the item. Whoever holds it may drive.
- If the engine is already running, it keeps running even if the key is taken away.
- In the inventory, a key shows the plate and the vehicle name.
Locksmith
The locksmith only serves the owner according to the framework vehicle table.
- Spare key: for a fee (
Config.Locksmith.CopyFee), fits the current lock. - Change lock: for a fee (
Config.Locksmith.LockFee), you get a new key. All old keys stop working. - Existing vehicles: vehicles from before Pepper Keys have no key yet. The first one is free (
Config.Locksmith.FirstFree).
If the key does not fit into the inventory, the player gets their money back.
Hotwiring
- Only without a matching key, with the tool
Config.Hotwire.Item(defaultlockpick,false= no tool needed). - Minigame: press space when the needle is in the zone. Difficulty depends on the vehicle class (
Config.Hotwire.Levels,Classes). - Success: the vehicle is open and the engine starts until it is parked or deleted.
- Failure: a cooldown (
Cooldown) and a chance that the tool breaks (ItemBreakChance). - Alarm with chance
AlarmChance: siren on the vehicle and the server eventpepper_keys:alarm. - Minimum police on duty:
MinPolice, counted with the jobs fromPoliceJobs.
Garage scripts
Pepper Keys only reads the framework vehicle table (owned_vehicles on ESX, player_vehicles on QBCore and Qbox) and never
writes to it. So it works with any garage script that uses this table. Taking a car out creates no new key, the player keeps
using the key they already have.
| Garage script | Framework | Table |
|---|---|---|
| esx_garage | ESX | owned_vehicles |
| qb-garages | QBCore | player_vehicles |
| qbx_garages | Qbox | player_vehicles |
| JG Advanced Garages | ESX, QBCore, Qbox | framework vehicle table |
| cd_garage | ESX, QBCore | framework vehicle table |
| okokGarage | ESX, QBCore | framework vehicle table |
| loaf_garage, renzu_garage | ESX | owned_vehicles |
| OP Garages v3 (OTHERPLANET) | ESX, QBCore, Qbox | framework vehicle table (per its docs) |
This list follows from the table each script uses. We have not tested Pepper Keys with each of these third-party scripts. If your garage script uses its own table, its vehicles are not locked.
Only one key script: remove other key scripts (e.g. qb-vehiclekeys, qbx_vehiclekeys, wasabi_carlock). If your garage script has a setting for the key system, set it to "none" or enter the Pepper Keys exports there.
OP Garages v3: taking cars out and parking them works without changes; OP Garages gives no key there (Config.KeysDependency falls back to none). Car contracts, fake plates and job or gang vehicles need their own integration in the OP Garages "editable" files: after a contract, call ChangeLock + CreateKey for the new owner so the old key stops working.
Other scripts that should hand out keys themselves (dealership, rental, fleet) call the exports below.
Commands and permissions
| Command | Who | What |
|---|---|---|
/pkeys give <plate> |
Admin | Create a key |
/pkeys lock <plate> |
Admin | Change the lock (old keys worthless) |
/pkeys open <plate> |
Admin | Unlock a vehicle |
Permissions: Admin = ACE pepper.keys.admin (ServerConfig.AdminAce) or a group from Config.AdminGroups. The command
only works in game, not in the server console. Every action is logged, optionally to a Discord webhook (ServerConfig.Webhook).
The command name is set in Config.AdminCommand.
Keys: U lock, K hotwire, E locksmith. Players can change them in their FiveM settings (Key Bindings → FiveM);
the defaults are Config.LockKey, HotwireKey and InteractKey.
Exports and events
Server exports:
exports.pepper_keys:CreateKey(src, plate, label) -- put a key into the inventory
exports.pepper_keys:HasKey(src, plate) -- does the player hold a matching key?
exports.pepper_keys:ChangeLock(plate) -- new lock, old keys worthless
exports.pepper_keys:RemoveKeys(src, plate) -- take away the keys for this plate
Events:
| Event | Side | Payload | Purpose |
|---|---|---|---|
pepper_keys:alarm |
server | { plate, coords } |
Car alarm while hotwiring, e.g. for your dispatch script |
AddEventHandler('pepper_keys:alarm', function(data)
print(('Car alarm: %s at %.1f, %.1f'):format(data.plate, data.coords.x, data.coords.y))
end)
Alternatively, add your own dispatch integration in bridge/server/dispatch.lua (open file).
FAQ
Pepper Keys does not start or stays inactive – what now?
ox_inventory, ox_lib, oxmysql and your framework must start before pepper_keys. Without ESX, QBCore or Qbox, or without a
running ox_inventory, the script reports in the console that it stays inactive.
The key has no image in the inventory.
Copy install/images/pepper_carkey.png to ox_inventory/web/images and restart the server.
My own car does not start.
Vehicles from before Pepper Keys have no key yet. Get one at the locksmith, the first one is free (Config.Locksmith.FirstFree).
A job vehicle is locked.
Only vehicles in the framework vehicle table or in pepper_keys_locks are locked. Check whether the plate is listed there.
"You are missing the right tool" when hotwiring.
The item from Config.Hotwire.Item (default lockpick) must be in your inventory. With Item = false no tool is needed.
/pkeys does nothing.
Set the ACE from the installation (add_ace group.admin pepper.keys.admin allow) or add your group to Config.AdminGroups. The
command has no effect in the server console.
Do I need to import the SQL file?
No. The table pepper_keys_locks is created automatically on start. install/pepper_keys.sql is only for database users that
cannot create tables.
Does Pepper Keys work with qs-inventory or qb-inventory?
No, the key is an ox_inventory item with metadata. Without ox_inventory the script stays inactive.
Can I use Pepper Keys together with qb-vehiclekeys?
No, use only one key script. Remove the others (qb-vehiclekeys, qbx_vehiclekeys, wasabi_carlock), otherwise they lock and unlock against each other.
How does my dealership or rental script hand out a key?
With the server export exports.pepper_keys:CreateKey(src, plate, label). When a car is resold, call ChangeLock(plate) first,
then CreateKey for the new owner.
How do I change texts or the language?
Language via Config.Locale ('de' or 'en'), texts in locales/de.json or locales/en.json. You change the item name in
ox_inventory/data/items.lua.
How do I move the locksmith or add more?
Change the coords in Config.Locksmith.Places or add entries with label, coords, radius and blip.
Can cheaters bypass the engine lock?
The engine lock runs on the client and can be bypassed by cheaters. Locking, ownership, item checks, fees and hotwiring are checked by the server.
How do I send the car alarm to my dispatch script?
Listen to the server event pepper_keys:alarm or add the call to your dispatch script in bridge/server/dispatch.lua.
Support
Discord → ticket (category "Script Support") at https://discord.gg/6NaFJWKDYu, link your purchase with /verify first.
Permanently tested on the Pepper Scripts dev server.
Changelog
Current: 1.0.0 (2026-11-08), first release. All changes are listed in CHANGELOG.md in the resource.
Found a mistake? Report it on Discord.