Developers & Integration
The script exposes a small set of server exports, so other resources can book a car into a yard or read where the yards are. All of them are server-side only. A client cannot call them.
Server exports
| Export | Returns |
|---|---|
ImpoundVehicle(plate, lotId, opts) | { plate, lotId, slot }, or { error = '<reason>' } |
GetLots() | an array of lots with their public points and free bays |
RemoveUnownedVehicles(plates, opts) | { n, plates }: the unowned records it removed |
DepotParkVehicle(lotId, car, opts) | { slot }, or { error } |
RemoveDepotParked(plates) | { n } |
ImpoundVehicle
Books a car into a yard through the same path every other intake uses, with the same checks, record, and fee rules:
local res = exports['vs-impoundjob']:ImpoundVehicle(plate, lotId, {
towedBy = 'LSPD', -- shown as who brought it in
reason = 'Evidence', -- up to 64 characters, goes on the record
fee = 1500, -- optional: this car's base release fee, instead of the lot's
})
if res.error then
print(('Could not impound %s: %s'):format(plate, res.error))
else
DeleteEntity(vehicle) -- the export records the car; removing the entity is up to you
end
- A plate the framework knows is booked in as owned, and taken out of the owner's garage. Any other plate comes in unowned and ages out on the unowned timer.
- The call is refused for:
- an unknown lot;
- a lot that does not hold vehicles (a Public Job depot);
- a plate that is already impounded.
- The car is parked in the first free bay and drawn for every player. Optional
opts.model,opts.modelHash, andopts.appearancedescribe the car when the framework has no record of it.
GetLots
for _, lot in ipairs(exports['vs-impoundjob']:GetLots()) do
print(lot.id, lot.name, lot.service, lot.job)
end
Each entry is a copy, never the live record:
id,nameservice:'npc','player','auto', or'nowl'(Public Job)job: the lot's framework job, ornilrobbable: the admin's "This yard can be robbed" switch. The job itself never acts on it, but other resources can.- Public points:
blip,office,gate(a list),enterGate,handover,impound,safe bays: the yard's empty bays only, as coordinates. It is empty at a depot.
Use it to find the nearest yard, put a yard on a phone app map, or stand a vehicle in a free bay without clipping an impounded one.
RemoveUnownedVehicles
Takes a plate or a list of plates and removes the matching records that have no owner. Owned cars always leave through the counter, never through this. Pass { class = 'unowned' } to restrict it further.
DepotParkVehicle / RemoveDepotParked
These stand a car in a Public Job depot's bay (car = { plate, model, modelHash, color1, color2 }, opts = { slot, keep }) and take keep cars back out. Errors are short strings:
'starting','database offline''no such lot','not a depot''parking off','no bays','no such bay','taken'
They are mainly useful for dressing a depot for screenshots or recordings.
Radial menus and police tools
The simplest hook is to run the command from the client. It opens the same request screen, with the same server checks:
ExecuteCommand('requesttow') -- Config.TowCommand: the officer's forced-removal request
ExecuteCommand('chiama') -- Config.CallCommand: a player's assistance call
Use whatever names you set in config.lua. The stock tow job's events are not implemented, so point any existing radial-menu tow entry at the command instead. See Dependencies: replacing qb-towjob.
Usable item export
The traffic cone item calls the client export vs-impoundjob.cone, which opens or closes the cone placer. Register it on the item as shown on the Items page.
The database
Everything lives in 12 tables, created automatically. The ones an MDT or police tool is most likely to read:
| Table | Holds |
|---|---|
imp_vehicles | Every car currently held: plate (unique), model, owner, lot_id, slot, class (owned / unowned), fee, towed_by, reason, created_at. A row is deleted when the car is released, so this is a presence list, not a history. |
imp_lots | The lots: id, name, job, and the placements as JSON |
imp_ledger | Every money movement per lot, with its reason and actor |
imp_freelance_drivers | Public Job reputation, truck tier, cars brought in, and suspension, per character |
The rest are:
imp_settingsimp_slotsimp_fleetimp_accountsimp_kvimp_accreditationimp_lot_statsimp_freelance_pending
install.sql shows the full schema. Read freely, but write through the exports. The script caches its data in memory, so a row changed behind its back is not seen until a restart.
Framework vehicle records
When an owned car is impounded and released, the script writes the framework's own vehicle table:
ESX owned_vehicles | QBCore / Qbox player_vehicles | |
|---|---|---|
| Impounded | stored = 1, parking = NULL, pound = <lot name> | state = 2 |
| Released | stored = 0, parking = NULL, pound = NULL | state = 0 |
A garage or police script that reads these columns sees an impounded car as impounded. Owners are matched by owned_vehicles.owner (the ESX identifier) or player_vehicles.citizenid.
Companion resource
The receptionist, both clerks, and the Public Job dispatcher talk through vs-npc-dialogue exports, so keep it updated in lockstep with the script. See its docs.
Building an integration and want an export or event that is not listed here? Open a ticket on Discord and we will point you at the right seam.