# Developer > Developer API reference for ML Vehicle Persistence Category: VEHICLE PERSISTENCE · Source: https://miciomods.it/docs/ml-vehicle-persistence-developer · Last updated: 2026-09-26 ## Overview Other resources can coordinate persistence through server exports and the open/server.lua hooks. The open/ folder holds ownership and garage-state logic that can be adapted for the server framework. ## Server Exports ### Coordination - `DoNotSave(plateOrNetId, reason?)`: Exclude a vehicle from persistence and remove it if already tracked. Accepts a plate, a network id, or an entity handle - `ExcludeFromPersistence(plateOrNetId, reason?)`: Alias of `DoNotSave` - `RemoveExclusion(plate)`: Clear an exclusion - `IsExcludedFromPersistence(plate)`: Returns `true` if excluded - `LockVehicle(plate)`: Temporarily block persistence (during towing, mechanic work). Auto-expires after 5 minutes - `UnlockVehicle(plate)`: Release a lock - `IsVehicleLocked(plate)`: Returns `true` if locked ### Vehicle Control - `PurgeVehicle(plateOrNetId, keepInWorld?)`: Remove a vehicle from persistence. Despawns it unless `keepInWorld` is `true` - `UpdateVehicle(plateOrNetId)`: Force a save and refresh the vehicle's stored properties from its owner client - `ClaimVehicle(plateOrNetId, src)`: Register a vehicle as persistent and owned by the player `src` - `TransferPersistedVehicle(plate, newOwner)`: Reassign a persisted vehicle to another owner identifier - `PurgeOwner(ownerId)`: Remove every persisted vehicle belonging to an identifier. Returns the count removed - `SetVehiclePlate(plateOrNetId, newPlate)`: Move persistence to a new plate after a plate change - `RemovePersistedVehicle(plate)`: Drop a vehicle from persistence, keeping it in the world - `SetVehicleProtected(plate, state)`: Mark a tracked vehicle as exempt from the slot count, cleanup, decay and orphan removal. Returns false if the plate is not tracked. - `ClearBaseLink(plate)`: Remove a tracked vehicle's saved base flag link. ```lua exports.ml_vehicle_persistence:SetVehicleProtected(plate, true) exports.ml_vehicle_persistence:ClearBaseLink(plate) ``` ### Pause - `PausePersistence(state)`: Pause or resume all saving and claiming. Returns the new state - `IsPersistencePaused()`: Returns the current pause state ### Maintenance - `RunCleanup()`: Run the `Config.Cleanup` sweep once, outside its schedule. Returns the number of vehicles removed ### Query - `IsVehiclePersisted(plate)`: Returns `true` if the plate is persisted - `GetWorldVehicles()`: Returns every tracked vehicle - `GetVehicleStatus(plate)`: Returns `{ isPersisted, isExcluded, isLocked, exclusion, lock, vehicle }` - `GetVehicleCoords(plate)`: Returns a persisted vehicle's live coordinates when available, or its saved coordinates otherwise. GPS tampering does not replace these with the owner's frozen GPS position - `GetVehiclesCoords(plates)`: Returns a map of plate to coordinates - `GetVehiclesByFlag(flagId)`: Return tracked vehicles linked to a base flag. - `GetVehiclesByOwner(owner)`: Return tracked vehicles for an owner identifier. - `GetVehiclesInArea(coords, radius)`: Return tracked vehicles within the radius of a vector3 or coordinate table. - `CanStoreVehicle(plate)`: Return false, 'raid' when the vehicle is linked to a base under raid and storing is blocked; otherwise true. ```lua local byOwner = exports.ml_vehicle_persistence:GetVehiclesByOwner(owner) local nearby = exports.ml_vehicle_persistence:GetVehiclesInArea(coords, 100.0) local canStore, reason = exports.ml_vehicle_persistence:CanStoreVehicle(plate) ``` ## Client Exports - `PurgeVehicle(plateOrNetId)`: Drop a vehicle from persistence and delete it from the client side. Used by resources that delete vehicles on the client. Returns `true` when the request was accepted ## Deleting Vehicles From Another Resource With `Config.RespawnOnExternalDelete = false` (the default) nothing is needed: a plain `DeleteEntity` or an admin `/dv` drops the vehicle from persistence like every other script expects. With `Config.RespawnOnExternalDelete = true` every delete is undone by the respawn engine unless it is routed through the script. Either call the `PurgeVehicle` export, or add the shipped hook as the **first** script line of the deleting resource: **fxmanifest.lua** ```lua shared_script '@ml_vehicle_persistence/deletehook.lua' ``` > **WARNING:** First line > > The hook replaces the `DeleteEntity` and `DeleteVehicle` natives. A resource that caches them in a local before the hook loads bypasses it, so the `shared_script` line must come before every other script entry. The request is validated server-side: a tracked vehicle is only removed by an admin or by its own owner, and a locked vehicle is never touched. ## Server Handlers Located in `open/server.lua`. ### CanPersist **open/server.lua** ```lua function OpenServer.CanPersist(src, vehicle, plate, owner) return nil end ``` Ownership gate before a vehicle becomes persistent. Return `false` to block, `true` to force-allow for custom ownership systems, `nil` for the default owned-vehicles check. ### CanClaim **open/server.lua** ```lua function OpenServer.CanClaim(src, vehicle, plate) return nil end ``` Gate before a world vehicle is claimed by its first driver. Return `false` to block the claim, for example to require a hotwire item. ### FetchOwnedPlates **open/server.lua** ```lua function OpenServer.FetchOwnedPlates() return {} end ``` Returns an array of plate strings from the ownership database. Claiming never touches these plates. The default reads `player_vehicles` or `owned_vehicles`. ### IsPlateOwned **open/server.lua** ```lua function OpenServer.IsPlateOwned(plate) return false end ``` Authoritative single-plate check, consulted when a plate is missing from the cached registry, such as a car bought seconds earlier. Return `true` if the plate belongs to a player. ### FetchGaragedVehicles **open/server.lua** ```lua function OpenServer.FetchGaragedVehicles(src, owner) return {} end ``` Vehicles the player owns that are sitting in a garage right now, so the GPS item shows them as stored instead of a dead waypoint. Return an array of `{ plate, model?, garage? }`. The `garage` value is shown to the player as-is, so raw ids can be mapped to friendly names here. The default reads `player_vehicles` with `state = 1`. ### OnVehicleRestored **open/server.lua** ```lua function OpenServer.OnVehicleRestored(plate, owner) end ``` Fires for every vehicle put back into the world after a restart. The default updates player_vehicles on Qbox/QBCore. Adapt the hook for ESX or a custom garage. ### ImpoundVehicle **open/server.lua** ```lua function OpenServer.ImpoundVehicle(plate, owner, fee, impoundLot) end ``` Orphan cleanup with action = 'impound' routes database-owned vehicles here. The default updates player_vehicles on Qbox/QBCore; adapt the hook for ESX or a custom impound. Claimed World Vehicles are deleted instead. ### Lifecycle Hooks **open/server.lua** ```lua function OpenServer.OnVehiclePersisted(plate, owner) end function OpenServer.OnVehicleClaimed(plate, owner, src) end function OpenServer.OnVehicleRemoved(plate, owner, reason) end function OpenServer.OnGpsTampered(plate, owner, src) end function OpenServer.OnGpsInstalled(plate, owner, src) end ``` OnVehicleRemoved reports why a vehicle left persistence, including stored, excluded, destroyed, impounded, orphan_deleted, owner_purged, cleanup, admin_remove, admin_clear, deleted_by_client_hook, and resource-triggered removal. `OnGpsTampered` fires when a thief rips a vehicle's GPS out with the scanner item; `OnGpsInstalled` fires when the owner restores live tracking with a module. ## Client Handlers Located in `open/client.lua`. These listen for garage store events and drop the stored vehicle from persistence. Add your garage's event here: **open/client.lua** ```lua function OpenClient.NotifyStored(plate) TriggerServerEvent('ml_vehicle_persistence:server:vehicleStored', plate) end ``` ## Admin Integrations Provider tables in `open/integrations/` add rows and actions to vehicle inspection. Built-in providers check whether their resource is running. To add another provider, copy `open/integrations/example.lua`, remove its disabled guard and adapt its resource, rows and actions. ## Examples **Exclude a mission vehicle** ```lua local netId = NetworkGetNetworkIdFromEntity(vehicle) exports.ml_vehicle_persistence:DoNotSave(netId, 'mission') ``` **Refresh a vehicle after mechanic work** ```lua exports.ml_vehicle_persistence:UpdateVehicle(plate) ``` **Grant a vehicle to a player and persist it** ```lua exports.ml_vehicle_persistence:ClaimVehicle(netId, src) ```