> For the complete documentation index, see [llms.txt](https://acestudios.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://acestudios.gitbook.io/docs/jobs-and-economy/p2p-vehicle-marketplace/integrations.md).

# Garage & Key Integrations

Garage and vehicle key integrations, including writing your own adapter.

Integration adapters are in `integrations/` and are **not escrowed**, so you can read and extend them.

## Garages

When a vehicle is sold, or a rental ends, the marketplace places it in a garage.

| `Config.Garage.Resource` | Adapter file                         | How it works                                                            | Public garage list                                                                                                                  |
| ------------------------ | ------------------------------------ | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `okokgarage`             | `integrations/garage/okokgarage.lua` | Updates the vehicle table directly (okokGarage reads `owned_vehicles`). | Not exported. Falls back to garage names from the vehicle table.                                                                    |
| `esx_garage`             | `integrations/garage/esxgarage.lua`  | Updates the vehicle table.                                              | `exports.esx_garage:getGarages()`, public garages without job access.                                                               |
| `qb-garages`             | `integrations/garage/qbgarage.lua`   | Updates the vehicle table.                                              | If `qbx_garages` is running: `exports.qbx_garages:GetGarages()` (public car garages without groups). Otherwise vehicle table names. |
| `none`                   | Handled by the okokgarage adapter    | Plain vehicle-table storage.                                            | Vehicle table names.                                                                                                                |
| `custom`                 | `integrations/garage/custom.lua`     | Your own implementation.                                                | Your own implementation.                                                                                                            |

`Config.Garage.Enabled = false` never changes a vehicle's garage and hides the delivery picker.

### Custom garage adapter

Set `Config.Garage.Resource = 'custom'` and implement the functions in `integrations/garage/custom.lua` (server-side):

{% code title="integrations/garage/custom.lua" %}

```lua
Garage = {}

--- Store `plate` for `identifier` in `garageName`. Return true on success.
function Garage.Store(identifier, plate, garageName)
    return false
end

--- Put a vehicle that was transferred to `newIdentifier` into `garageName`. Return true on success.
function Garage.TransferOwnership(newIdentifier, plate, garageName)
    return false
end

--- Return true if `garageName` is a valid garage.
function Garage.IsValidGarage(garageName)
    return type(garageName) == 'string' and garageName ~= ''
end

--- Return { { name = 'garageId', label = 'Garage Label' }, ... } of public garages,
--- or nil to fall back to garage names found in the vehicle table.
function Garage.GetPublicGarages()
    return nil
end
```

{% endcode %}

Until they're implemented, `Store` and `TransferOwnership` log a `[GARAGE]` error and return `false`.

## Vehicle keys

Keys are given to buyers and renters, and removed when a rental ends.

| `Config.Keys.Resource` | Resource            | Give                                                                                | Remove                                   |
| ---------------------- | ------------------- | ----------------------------------------------------------------------------------- | ---------------------------------------- |
| `qbx_vehiclekeys`      | qbx\_vehiclekeys    | `GiveKeys(source, vehicle, true)`, only for a spawned vehicle                       | `RemoveKeys(source, vehicle, true)`      |
| `qbkeys`               | qb-vehiclekeys      | `GiveKeys(source, plate)`, or falls back to the `vehiclekeys:client:SetOwner` event | `RemoveKeys(source, plate)` if available |
| `wasabi_carlock`       | wasabi\_carlock     | `GiveKey(source, plate)`                                                            | `RemoveKey(source, plate)`               |
| `qs-vehiclekeys`       | qs-vehiclekeys      | `GiveServerKeys(source, plate, model, true)`                                        | `RemoveServerKeys(source, plate, model)` |
| `MrNewbVehicleKeys`    | MrNewbVehicleKeys   | `GiveKeysByPlate(source, plate)`                                                    | `RemoveKeysByPlate(source, plate)`       |
| `Renewed-Vehiclekeys`  | Renewed-Vehiclekeys | `addKey(source, plate)`                                                             | `removeKey(source, plate)`               |
| `default`              | Built-in            | Lets a renter lock/unlock their rented vehicle                                      | Revoked when the rental ends             |
| `custom`               | Your own            | `integrations/keys/custom.lua`                                                      | `integrations/keys/custom.lua`           |

{% hint style="info" %}
**qbx\_vehiclekeys:** owners get keys automatically when they take a vehicle out of their garage, so the marketplace only gives keys for a vehicle that's already spawned.

**qb-vehiclekeys:** versions without a `RemoveKeys` export can't remove keys. The renter keeps the key until they relog, but the vehicle itself is still taken back. A `[KEYS]` warning is logged.
{% endhint %}

### Built-in keys

With `Config.Keys.Resource = 'default'`, renters can lock and unlock their rented vehicle within 10 m using the command **`ace_marketplace_vehiclelock`**. It's registered as a key mapping named *"Lock/Unlock Rented Marketplace Vehicle"*, with the default key from `Config.Keys.LockKey` (unbound by default).

{% hint style="warning" %}
Built-in keys are only read by the marketplace itself. Other resources, such as your usual lock script, don't know about them.
{% endhint %}

### Custom keys adapter

Set `Config.Keys.Resource = 'custom'` and implement `integrations/keys/custom.lua`:

{% code title="integrations/keys/custom.lua" %}

```lua
Keys = {}

if IsDuplicityVersion() then
    --- Give `source` a key for `plate` (model is the spawn name / hash when known). Return true on success.
    function Keys.Give(source, plate, model)
        exports['my_keys']:GiveKey(source, plate) -- replace with your key resource's API
        return true
    end

    --- Remove `source`'s key for `plate`. Return true on success.
    function Keys.Remove(source, plate, model)
        exports['my_keys']:RemoveKey(source, plate) -- replace with your key resource's API
        return true
    end
else
    function Keys.HasKeys(plate)
        return false
    end
end
```

{% endcode %}

`my_keys` is a placeholder. Use your key resource's real exports. The shipped file logs a single `[KEYS]` warning and gives no keys until you implement it.

## Notifications

The framework adapters in `framework/` use **ox\_lib** notifications when `ox_lib` is started. On ESX, **okokNotify** is also checked. Otherwise the framework's native notification is used. No setup is needed.

## Photos

Vehicle photos need **screenshot-basic**. See [Configuration → Photos](/docs/jobs-and-economy/p2p-vehicle-marketplace/configuration.md#photos).
