> For the complete documentation index, see [llms.txt](https://docs.rahe.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.rahe.dev/our-scripts/taxi/integration.md).

# Integration

`rahe-taxi` has auto-detection for the most common fuel, vehicle key and garage resources. If you are running one of the supported systems, no setup is required — it just works.

If you use a custom or unsupported resource, you can plug it in by editing the corresponding file under `public/api/`. These files are unencrypted so you can adapt them to your systems.

> The detection runs in a `CreateThread` at resource start and picks the first matching resource (by `GetResourceState`). If none match, an error is printed and you must implement the integration yourself.

***

#### Fuel system <a href="#fuel-system" id="fuel-system"></a>

**File:** public/api/cl\_fuelsystem.lua (client-side)

**Supported out of the box**

* `LegacyFuel`
* `qs-fuelstations`
* `ox_fuel`
* `cdn-fuel`
* `lc_fuel`

**Function to implement**

```lua
function setVehicleFuel(vehicle, fuel)
    -- vehicle: entity handle (client-side)
    -- fuel:    number 0-100
end
```

This is called when an NPC taxi vehicle is spawned and needs its fuel level set.

**Adding your own fuel system**

Add a new `elseif` branch in the detection thread, then add a matching branch in `setVehicleFuel`:

```lua
elseif GetResourceState('my_fuel') ~= 'missing' then
    detectedFuelSystem = 'my_fuel'
```

```lua
elseif detectedFuelSystem == 'my_fuel' then
    exports['my_fuel']:SetFuel(vehicle, fuel)
```

If everything else fails, the script falls back to the native `SetVehicleFuelLevel`.

***

#### Vehicle keys system <a href="#vehicle-keys-system" id="vehicle-keys-system"></a>

**File:** public/api/sv\_vehiclekeys.lua (server-side)

**Supported out of the box**

* `qbx_vehiclekeys`
* `qs-vehiclekeys`
* `cd_garage`
* `wasabi_carlock`
* `Renewed-Vehiclekeys`
* `qb-vehiclekeys`

**Function to implement**

```lua
function unlockVehicleDoors(playerId, vehNetId, vehicle, plate)
    -- playerId: server id of the player
    -- vehNetId: network id of the vehicle
    -- vehicle:  server-side entity handle
    -- plate:    license plate string
    -- return true on success
end
```

Called when a passenger gets into an NPC driver's taxi so the doors can be unlocked for them.

**Adding your own keys system**

```lua
elseif GetResourceState('my_keys') ~= 'missing' then
    detectedKeySystem = 'my_keys'
```

```lua
elseif detectedKeySystem == 'my_keys' then
    exports['my_keys']:GiveTemporaryKey(playerId, plate)
    return true
```

The fallback unlocks the vehicle via the native `SetVehicleDoorsLocked(vehicle, 1)`.

***

#### Garage system <a href="#garage-system" id="garage-system"></a>

**File:** public/api/sv\_garagesystem.lua (server-side)

**Supported out of the box**

* `qbx_vehicles`
* `qb-garages`
* `esx_garage`

**Function to implement**

```lua
function getPlayerOwnedVehicles(playerIdentifier)
    -- playerIdentifier: citizenid (qb/qbx) or identifier (esx)
    -- return an array of vehicle tables in the format below
end
```

Each entry returned **must** have this shape:

```lua
{
    plate = 'ABC123',          -- string, trimmed (no surrounding spaces)
    name  = 'Brand Model',     -- display name shown in the UI
    model = 'taxi',            -- spawn name (must match VEHICLES config key)
}
```

This is used by drivers to choose which of their owned vehicles to put on duty.

**Vehicle naming**

Display names come from the `VEHICLES` config (`shared/vehicles.lua`). If a model is not present there, an error is logged and the vehicle is skipped (qb/qbx) or returned with the raw model name (esx). Add your custom vehicles to that config to fix this.

**Adding your own garage system**

Add detection and a query branch. Example for a custom MySQL-backed garage:

```lua
elseif GetResourceState('my_garage') ~= 'missing' then
    detectedGarageSystem = 'my_garage'
```

```lua
elseif detectedGarageSystem == 'my_garage' then
    local rows = MySQL.query.await('SELECT plate, model FROM my_garage WHERE owner = ?', { playerIdentifier })
    for _, v in ipairs(rows) do
        local info = VEHICLES[v.model]
        if info then
            playerVehicles[#playerVehicles + 1] = {
                plate = v.plate,
                name  = info.brand .. ' ' .. info.name,
                model = v.model,
            }
        end
    end
    return playerVehicles
```

#### Dispatch system <a href="#dispatch-system" id="dispatch-system"></a>

**File:** public/api/cl\_dispatch.lua (client-side)

Used by the in-app safety report feature. When a rider or driver sends a safety report from the UI, the script forwards it to your dispatch / police-alert resource.

**Supported out of the box**

* `ps-dispatch`
* `cd_dispatch`
* `qs-dispatch`
* `qb-policejob` (default `police:server:policeAlert` event)

**Function to implement**

```lua
function alertPolice(vehicleName, vehiclePlate, message, type)
    -- vehicleName:  display name of the vehicle (e.g. "Albany Taxi")
    -- vehiclePlate: license plate string
    -- message:      free-text message written by the player
    -- type:         'rider' or 'driver' — used to pick the locale string
end
```

The localized text is built from `RiderSafetyReport` / `DriverSafetyReport` in the locale files. The current player's coordinates can be obtained inside the function via `GetEntityCoords(PlayerPedId())`.

**Adding your own dispatch system**

Add detection and a handler branch:

```lua
elseif GetResourceState('my_dispatch') ~= 'missing' then
    detectedDispatchSystem = 'my_dispatch'
```

```lua
elseif detectedDispatchSystem == 'my_dispatch' then
    exports['my_dispatch']:CreateAlert({
        title = '10-90 - Taxi Safety Report',
        message = text,
        coords = coords,
        jobs = { 'police' },
    })
```
