Exports & API Reference
Net events, o-link callbacks, entity statebags, and the oxide-police recording integration surface.
oxide-baitcar does not expose Lua exports. Its public integration surface is the set of net events and o-link callbacks listed below. The oxide-police recording integration is documented for completeness, but it is intentionally not a public API — see the Recording Integration note at the bottom.
Net Events: Server ← Client
All inbound events run through Permissions.IsAllowed(source) and (where applicable) playerIsInVehicle to gate operations on the source actually being an authorized officer or the suspect physically in the vehicle. Plate lookups validate against active deployments.
| Event | Payload | Behavior |
|---|---|---|
oxide:baitcar:server:install | vehicleNetId: number | Installs the chip on the source's current vehicle. Requires the officer to be in the vehicle, the vehicle to be an automobile, the plate to be unique, and the officer to hold Config.ChipItem. Consumes one chip on success. |
oxide:baitcar:server:setLocked | plate: string, locked: boolean | Toggles doors locked / unlocked. |
oxide:baitcar:server:setEngineDisabled | plate: string, disabled: boolean | Kills or restores the engine. |
oxide:baitcar:server:setSteering | plate: string, mode: string | Sets steering mode. Valid values: 'off', 'lock', 'left', 'right'. |
oxide:baitcar:server:setSpeedLimit | plate: string, enabled: boolean | Engages or releases the speed limiter at Config.SpeedLimitMph. |
oxide:baitcar:server:setStrobe | plate: string, enabled: boolean | Toggles the headlight strobe. |
oxide:baitcar:server:setAlarm | plate: string, enabled: boolean | Toggles the vehicle alarm. |
oxide:baitcar:server:honk | plate: string | Fires a single horn pulse for Config.HornDurationMs. |
oxide:baitcar:server:decommission | plate: string | Clears the deployment, removes the statebag, and writes a decommissioned audit row. |
oxide:baitcar:server:trigger | vehicleNetId: number | Fired by a non-LEO driver client when the drive-off thresholds are met. The server validates the source is the actual driver before processing. Rate-limited; one-shot per deployment. |
oxide:baitcar:server:entryNotify | vehicleNetId: number | Fired by a non-LEO client when first sitting in the driver seat of a flagged vehicle. Triggers an olink.dispatch.CreateAlert broadcast using Config.EntryDispatch. Rate-limited; one alert per plate every 30 seconds. |
oxide:baitcar:server:vehicleSearch | vehicleNetId: number | Fired by the civilian client after using Config.RemovalToolItem inside a vehicle and completing the search progress bar. Server re-verifies the source is seated in the vehicle, then rolls Config.RemovalSuccessChance on a bait car; returns identical "nothing found" messaging on a non-bait vehicle, failed roll, missing entity, not-in-vehicle reject, or rate-limited call. |
Net Events: Client ← Server
| Event | Payload | Behavior |
|---|---|---|
oxide:baitcar:client:install | none | Prompts the client to begin the install flow. Fired when an authorized officer uses the Config.ChipItem. |
oxide:baitcar:client:trySearchVehicle | none | Prompts the client to begin the chip-removal flow. Fired when any player uses the Config.RemovalToolItem. The client silently no-ops if the player is not in a vehicle; otherwise runs the search progress bar and fires oxide:baitcar:server:vehicleSearch. |
oxide:baitcar:client:remoteToggle | none | Toggles the remote controller UI. Fired when an authorized officer uses the Config.RemoteControllerItem (only when Config.UseRemoteController = true). |
oxide:baitcar:client:dashcamTuneOpen | none | Opens the dashcam tuner menu. Fired by the /baitcardashcamtune server command. |
oxide:baitcar:client:deploymentChanged | plate: string, payload: table | nil | Broadcast to every authorized-job client whenever a deployment is added, mutated, or removed. payload is the full deployment record (with mutable state) or nil to indicate removal. |
oxide:baitcar:client:event | item: table | Live event-feed item, broadcast to authorized clients whenever the server writes an audit row. Shape: { type, plate, officerCharId, suspectCharId, timestamp }. |
oxide:baitcar:client:applyWanted | level: number | Server tells a suspect's client to call SetPlayerWantedLevel with the configured Config.FakeWantedLevel. Only fired on trigger when the value is > 0. |
oxide:baitcar:client:radialAction | args: table | string | Internal: dispatched by the radial submenu items. Routes to either open_manager or watch_nearest. Not intended for external triggering. |
Callbacks
oxide-baitcar registers o-link callbacks through the shared Callback.Register / Callback.Trigger helpers.
| Name | Direction | Returns | Notes |
|---|---|---|---|
oxide:baitcar:getDeployments | client → server | table[] of deployment records | Public. Returns the full active deployment list. Returns an empty list if the caller is not in Config.AllowedJobs. |
oxide:baitcar:server:video:getUploadUrls | client → server | provider-specific URL payload | Internal. Recording pipeline — proxies through oxide-police. |
oxide:baitcar:server:video:uploadDiscord | client → server | upload result | Internal. Recording pipeline — proxies through oxide-police. |
oxide:baitcar:server:video:saveRecording | client → server | { row, error } | Internal. Recording pipeline — proxies through oxide-police. |
Trigger from the client like:
olink = exports['o-link']:olink()
Callback = olink.callback
local deployments = Callback.Trigger('oxide:baitcar:getDeployments')
for _, d in ipairs(deployments or {}) do
print(d.plate, d.officerCharId, d.locked, d.engineDisabled, d.triggered)
endEntity Statebags
oxide-baitcar replicates state across the network using entity-scoped statebags. Statebags are scoped to clients with the entity in scope, so deployments are not leaked to clients that aren't physically near the vehicle.
oxide:baitcar
Set on a bait car entity for as long as the deployment is active. Cleared on decommission, civilian removal, or resource stop.
| Field | Type | Description |
|---|---|---|
plate | string | The vehicle's number plate text (trimmed). |
locked | boolean | Door lock state. |
engineDisabled | boolean | Engine kill state. |
speedLimit | boolean | Speed limiter state. |
strobe | boolean | Strobe state. |
alarm | boolean | Alarm state. |
steering | string | 'off', 'lock', 'left', or 'right'. |
triggered | boolean | One-shot trigger flag. true after the drive-off has fired. |
Sensitive deployment fields (the deploying officer's character id, their server source, the install timestamp) are deliberately omitted from the statebag — they only exist server-side and on authorized-officer clients (delivered via oxide:baitcar:client:deploymentChanged events).
oxide:baitcar:horn
A short-lived statebag used to pulse the horn. Each pulse increments a nonce.
| Field | Type | Description |
|---|---|---|
nonce | number | Monotonically increasing per-deployment counter. Clients fire the horn on every change. |
durationMs | number | Pulse length in milliseconds. |
Clients with the entity in scope listen for changes via AddStateBagChangeHandler('oxide:baitcar:horn', ...) and call StartVehicleHorn. The use of a separate statebag (rather than a global TriggerClientEvent) means the horn pulse is only delivered to clients that already know the bait car exists.
Recording Integration (oxide-police)
oxide-baitcar integrates with oxide-police for dashcam clip recording. This is not a public API and not an o-link namespace:
- The integration is hardcoded to
oxide-police(POLICE_RESOURCE = 'oxide-police'). - Every call site gates on
GetResourceState('oxide-police') == 'started'. A server withoutoxide-policehas the recording pipeline silently no-op. - The calls are direct
exports['oxide-police']:GetVideoUploadUrls(...),exports['oxide-police']:UploadVideoToDiscord(...), andexports['oxide-police']:SaveVideoRecording(...)and run insidepcallto handle export errors without leaving the NUI callback unresolved.
This is intentional. oxide-police is the only supported police backend for the recording integration; an o-link abstraction would imply pluggable backends that do not exist. If you ship your own MDT, the recording pipeline is not an integration point — it will not call into your resource. Disable recording with Config.Recording.enabled = false and the rest of the system continues to work normally.