Impound Job Developers & Integration

•5 min read

View Impound Job Script in the WXMAPS store

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

ExportReturns
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, and opts.appearance describe 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, name
  • service: 'npc', 'player', 'auto', or 'nowl' (Public Job)
  • job: the lot's framework job, or nil
  • robbable: 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:

TableHolds
imp_vehiclesEvery 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_lotsThe lots: id, name, job, and the placements as JSON
imp_ledgerEvery money movement per lot, with its reason and actor
imp_freelance_driversPublic Job reputation, truck tier, cars brought in, and suspension, per character

The rest are:

  • imp_settings
  • imp_slots
  • imp_fleet
  • imp_accounts
  • imp_kv
  • imp_accreditation
  • imp_lot_stats
  • imp_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_vehiclesQBCore / Qbox player_vehicles
Impoundedstored = 1, parking = NULL, pound = <lot name>state = 2
Releasedstored = 0, parking = NULL, pound = NULLstate = 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.