> For the complete documentation index, see [llms.txt](https://pepper-scripts.gitbook.io/pepper-scripts-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pepper-scripts.gitbook.io/pepper-scripts-docs/tools-ui/pepper-keys.md).

# Pepper Keys

Vehicle keys as real items – whoever holds the key drives the car. For ESX, QBCore and Qbox with ox\_inventory.

{% hint style="success" %}
✅ **Get Pepper Keys:** <https://shop.pepperscripts.de/package/7797871>
{% endhint %}

{% hint style="info" %}
🧪 **Tested on our dev server:** Of course we test all scripts continuously on our own dev server “Pepper Scripts”.
{% endhint %}

## 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

1. Copy the folder to `resources/[pepper]/pepper_keys`.

   > **Do not rename the folder.** Other scripts call `exports.pepper_keys`, which only works with the name `pepper_keys`.
2. Add the entry from `install/items/ox_inventory.txt` to `ox_inventory/data/items.lua`.
3. Copy `install/images/pepper_carkey.png` to `ox_inventory/web/images`.
4. In your `server.cfg`, after your framework, `oxmysql`, `ox_lib` and `ox_inventory`:

```cfg
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
```

5. 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

1. As an admin, type `/pkeys give <plate>` for one of your vehicles. The key is now in your inventory.
2. Press **U** at the vehicle: it locks or unlocks with a light signal.
3. Get in: with the key the engine starts. Drop the key, get out and back in: the engine stays off.
4. Without a key and with a `lockpick` in your inventory, press **K** and play the minigame.
5. 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

```lua
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

```lua
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

```lua
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` (default `lockpick`, `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 event `pepper_keys:alarm`.
* Minimum police on duty: `MinPolice`, counted with the jobs from `PoliceJobs`.

## 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:**

```lua
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 |

```lua
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

Open a ticket in our [Discord](https://discord.gg/6NaFJWKDYu) (category “Script Support”) and link your purchase with `/verify` first.

## Changelog

Current: **1.0.0** (2026-11-08), first release. All changes are listed in `CHANGELOG.md` in the resource.
