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.

EventPayloadBehavior
oxide:baitcar:server:installvehicleNetId: numberInstalls 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:setLockedplate: string, locked: booleanToggles doors locked / unlocked.
oxide:baitcar:server:setEngineDisabledplate: string, disabled: booleanKills or restores the engine.
oxide:baitcar:server:setSteeringplate: string, mode: stringSets steering mode. Valid values: 'off', 'lock', 'left', 'right'.
oxide:baitcar:server:setSpeedLimitplate: string, enabled: booleanEngages or releases the speed limiter at Config.SpeedLimitMph.
oxide:baitcar:server:setStrobeplate: string, enabled: booleanToggles the headlight strobe.
oxide:baitcar:server:setAlarmplate: string, enabled: booleanToggles the vehicle alarm.
oxide:baitcar:server:honkplate: stringFires a single horn pulse for Config.HornDurationMs.
oxide:baitcar:server:decommissionplate: stringClears the deployment, removes the statebag, and writes a decommissioned audit row.
oxide:baitcar:server:triggervehicleNetId: numberFired 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:entryNotifyvehicleNetId: numberFired 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:vehicleSearchvehicleNetId: numberFired 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

EventPayloadBehavior
oxide:baitcar:client:installnonePrompts the client to begin the install flow. Fired when an authorized officer uses the Config.ChipItem.
oxide:baitcar:client:trySearchVehiclenonePrompts 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:remoteTogglenoneToggles the remote controller UI. Fired when an authorized officer uses the Config.RemoteControllerItem (only when Config.UseRemoteController = true).
oxide:baitcar:client:dashcamTuneOpennoneOpens the dashcam tuner menu. Fired by the /baitcardashcamtune server command.
oxide:baitcar:client:deploymentChangedplate: string, payload: table | nilBroadcast 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:eventitem: tableLive event-feed item, broadcast to authorized clients whenever the server writes an audit row. Shape: { type, plate, officerCharId, suspectCharId, timestamp }.
oxide:baitcar:client:applyWantedlevel: numberServer 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:radialActionargs: table | stringInternal: 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.

NameDirectionReturnsNotes
oxide:baitcar:getDeploymentsclient → servertable[] of deployment recordsPublic. Returns the full active deployment list. Returns an empty list if the caller is not in Config.AllowedJobs.
oxide:baitcar:server:video:getUploadUrlsclient → serverprovider-specific URL payloadInternal. Recording pipeline — proxies through oxide-police.
oxide:baitcar:server:video:uploadDiscordclient → serverupload resultInternal. Recording pipeline — proxies through oxide-police.
oxide:baitcar:server:video:saveRecordingclient → 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)
end

Entity 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.

FieldTypeDescription
platestringThe vehicle's number plate text (trimmed).
lockedbooleanDoor lock state.
engineDisabledbooleanEngine kill state.
speedLimitbooleanSpeed limiter state.
strobebooleanStrobe state.
alarmbooleanAlarm state.
steeringstring'off', 'lock', 'left', or 'right'.
triggeredbooleanOne-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.

FieldTypeDescription
noncenumberMonotonically increasing per-deployment counter. Clients fire the horn on every change.
durationMsnumberPulse 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 without oxide-police has the recording pipeline silently no-op.
  • The calls are direct exports['oxide-police']:GetVideoUploadUrls(...), exports['oxide-police']:UploadVideoToDiscord(...), and exports['oxide-police']:SaveVideoRecording(...) and run inside pcall to 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.

Next Steps