Exports & API Reference

The developer surface of oxide-ems — exports, global state, player and entity statebags, events, and the compatibility surface.

The developer surface of oxide-ems — what other resources can read, call and listen to.

oxide-ems is a consumer of o-link, not a provider. It does not register an o-link namespace, so there is no olink.ems.*. Integration happens through the exports, events and statebags below.

Exports

Server

-- Read one setting's current effective value (the database value, not the file default).
local interval = exports['oxide-ems']:GetSetting('SalaryInterval')

-- Write one setting. Persists to the database, mirrors to clients and applies live.
exports['oxide-ems']:SetSetting('SalaryInterval', 600000)

GetSetting takes any top-level setting key — the same keys documented in Configuration (Revive, Beds, Surgery, Dispatch, and so on) — and returns the whole value, table or scalar.

SetSetting writes it back and always returns true. It performs no validation, so prefer the in-game editor (/ems settings) for anything a human is doing; this export is for scripted setup.

Server (QBCore only)

local doctors = exports['oxide-ems']:GetDoctorCount()

Number of medics currently on duty, across every department. Registered only when QBCore is the detected framework, as the replacement for the export qb-ambulancejob provided.

The matching QBCore callback is also registered:

QBCore.Functions.TriggerCallback('hospital:GetDoctors', function(count) end)

On any framework, the same number is always readable from GlobalState['oxide:ems:onduty'] — that is the portable way to ask.

Global state

Server-written, readable from anywhere.

KeyValueNotes
oxide:ems:ondutynumberTotal on-duty medics across all departments.
oxide:ems:beds:<facilityId>{ total, occupied }total = placed beds at that hospital. occupied is a map of bed index (as a string) to true.
oxide:ems:xraymachine:<facilityId>{ [pointId] = patientServerId }Which x-ray machines have a patient positioned in them. pointId is a string.
oxide:ems:surgerytable:<facilityId>{ [pointId] = { src, name } }Which operating tables are occupied, and by whom.
oxide-ems:configstring[]The list of setting keys currently mirrored to clients.
oxide-ems:config:<key>(varies)One setting's value, mirrored per key so clients can read the effective config without a callback.

Global state survives a resource restart, so these are republished at boot.

Player statebags

Replicated, so any client can read them for any player.

oxide:ems:duty

Player(src).state['oxide:ems:duty']
-- { deptId, deptName, gradeRank, facilityId }   -- on duty
-- nil                                            -- off duty

The authoritative duty state. Presence means on duty. This is the right thing for a HUD or a third-party script to read — do not keep your own mirror, because duty can be set and cleared server-side (a firing, a department deletion, a multi-job switch) without the player's client ever asking for it.

oxide:ems:triage

Player(src).state['oxide:ems:triage']
-- { critical, stabilized, paused, expiresAt, serverNow }   -- downed or dead
-- nil                                                       -- otherwise
FieldMeaning
criticalToo badly hurt for a street revive — must be stabilized, transported and revived at a bed.
stabilizedA medic has stabilized them; their bleedout timer is frozen.
pausedThe superset a client should freeze on: stabilized or under a procedure hold (a medic is actively working on them).
expiresAtWhen the stabilization lapses, as a Unix timestamp in seconds. Absent when not stabilized.
serverNowThe server's clock at the moment the bag was written. Compute expiresAt - serverNow when you receive it and count down locally — no clock sync needed.

oxide:ems:downed

Player(src).state['oxide:ems:downed']
-- { phase = 'downed'|'dead', bleedoutEnd?, respawnEnd?, serverNow }
-- nil when alive

Only written on QBCore and ESX, where oxide-ems runs the downed/dead loop. On Qbox, qbx_medical owns that state and this bag stays nil; on Oxide Core, the death provider owns it.

bleedoutEnd is present in the downed phase, respawnEnd in the dead phase, both as Unix timestamps in seconds with the same serverNow countdown pattern.

For a portable downed check across all frameworks, use o-link instead:

if olink.death.IsPlayerDowned(src) or olink.death.IsPlayerDead(src) then ... end

Entity statebags — fleet vehicles

Written by the server on every spawned fleet vehicle. Clients never write these.

KeyValueNotes
oxide:ems:fleetnumberThe vehicle's database row id. This is the fleet identity — never trust a bare network id to identify a fleet vehicle across sessions.
oxide:ems:fleetState{ plate, properties, livery, extras, fuel, body_health, engine_health }The visual and mechanical state the first owning client applies.
oxide:ems:fleetDecoratedtrueSet once a client has applied the above.
oxide:ems:bodyHealth / oxide:ems:engineHealthnumberServer-mirrored damage, fed by driver telemetry. Server-side health natives are unreliable while a client owns the entity, so read these instead.
oxide:platestringThe server-issued plate. A cross-resource convention shared with other Oxide resources.

Events

Server-side, safe to listen to

AddEventHandler('oxide:ems:server:initialized', function() end)
AddEventHandler('oxide:ems:server:settingsReady', function() end)
AddEventHandler('oxide:ems:server:departmentsChanged', function(reason, data) end)
AddEventHandler('oxide:ems:server:respawnPointsChanged', function(points) end)
AddEventHandler('oxide:ems:medicJobMirror', function(action, charId, jobName, gradeRank, jobLabel) end)
EventFires when
oxide:ems:server:initializedEvery module has loaded and the resource is ready.
oxide:ems:server:settingsReadySettings have been rebuilt from the database. Anything that reads a setting at boot must wait for this.
oxide:ems:server:departmentsChangedAny department, facility, grade, garage or vehicle changed. reason is a short description of what changed (department created, facility updated, …); data carries the affected ids.
oxide:ems:server:respawnPointsChangedThe hospital respawn point registry was rebuilt. Carries the full list.
oxide:ems:medicJobMirrorA medic was hired, promoted or fired. action is hired, gradeChanged or fired. This is what the g-multijob bridge listens to; use it to mirror EMS employment into your own systems.

Client-side, safe to listen to

RegisterNetEvent('oxide:ems:departmentsUpdated', function() end)
RegisterNetEvent('oxide:ems:medicDataChanged', function() end)
RegisterNetEvent('oxide:ems:forceClockOut', function() end)
AddEventHandler('oxide-ems:client:configUpdated', function(key) end)
EventFires when
oxide:ems:departmentsUpdatedDepartment data changed; clients rebuild their interaction points and blips.
oxide:ems:medicDataChangedThis player's employment changed.
oxide:ems:forceClockOutThe server clocked this player out.
oxide-ems:client:configUpdatedA setting changed. key is the setting that changed, or nil on the initial full load. Local to this resource's client scope.

Internal events — do not trigger these

These carry the resource's own state between its server and client sides. They validate their input, so triggering them from outside will not corrupt anything, but they are not an API and their shapes can change:

oxide:ems:client:bedEnter / bedExit / bedHealTick, vehicleEnter / vehicleExit, stretcherAttach / stretcherDetach, xrayEnter / xrayExit / xrayScreen, surgeryEnter / surgeryExit, runRespawnCutscene, openSettings, runDiag, oxide:ems:openAdminPanel, oxide:ems:vehicleRelinked / vehicleUntracked / vehicleDestroyed, and the oxide:ems:server:* net events (distress, reportDeath, reportReinjury, surgeryLeave, xrayLeave, xrayClearScreen, compat:qb:enterLaststand, reportVehicleState, reportVehicleType, fleetDecorated).

Compatibility surface

These are the events your framework's ambulance job used to own. oxide-ems re-registers them so existing resources keep working. Trigger them exactly as you did before.

All frameworks

EventDirectionEffect
hospital:server:emergencyAlertclient → serverRaises an EMS alert at the caller's position and notifies on-duty medics. Net-triggered only.
hospital:server:ambulanceAlert (text)client → serverSame, with a custom message. This is what police "officer down" relays use. Net-triggered only.
hospital:client:CheckStatusserver → clientOpens the examine overlay on the nearest patient.
hospital:client:TreatWoundsserver → clientSame.
hospital:client:RevivePlayerserver → clientRuns the normal validated revive on the nearest downed person.

QBCore only

EventDirectionEffect
hospital:client:Reviveserver → clientFully revives and heals the target.
hospital:client:KillPlayerserver → clientKills the target.
hospital:client:SetLaststandserver → clientPuts the target into the downed phase. Stock QBCore never registered this; oxide-ems does, which is what makes o-link's DownPlayer work on QBCore.
hospital:client:adminHealserver → clientFully heals and resets hunger and thirst.
hospital:server:SetDeathStatus (bool)client → serverKeeps the isdead metadata accurate.
hospital:server:SetLaststandStatus (bool)client → serverKeeps the inlaststand metadata accurate.
hospital:server:resetHungerThirstclient → serverResets hunger and thirst to full.

qb-inventory, qb-phone, qb-hud and qb-radialmenu all read the isdead and inlaststand metadata, and oxide-ems keeps both truthful through every transition.

ESX only

EventDirectionEffect
esx_ambulancejob:revive (playerId)eitherRevives the target. Triggered server-side by another resource it acts immediately; triggered over the net, the caller must be an on-duty medic or an admin.

The Player(src).state.isDead statebag is kept accurate throughout, and esx:onPlayerSpawn (plus esx_basicneeds:resetStatus and playerSpawned) is re-fired after every revive and respawn so ESX's own death detection and its add-ons re-arm.

txAdmin

txAdmin:events:healedPlayer is handled on QBCore and ESX — the heal button in the txAdmin panel revives the target, including the "heal everyone" form.

Usable items

The medical items your framework's ambulance job registered are re-registered by oxide-ems, with their original healing behaviour and one improvement: the item is only consumed when the action completes, where the stock resources consumed it up front.

FrameworkItems
QBCoreifaks, bandage, painkillers, firstaid
Qboxifaks, bandage, painkillers, firstaid
ESXmedikit, bandage

firstaid routes into the normal revive flow on the nearest downed person, and the revive pipeline consumes it itself on success — it is never removed twice.

medical_bag is registered on every framework and unpacks into field supplies.

Integrating a dispatch resource

oxide-ems raises alerts through olink.dispatch.CreateAlert. Among the dispatch adapters o-link ships, oxide-dispatch is the only one that implements the server-side CreateAlert — the others provide a client-side send only.

With any other dispatch resource, alerts are skipped and a debug line is logged; nothing errors. On-duty medics still receive the direct notifications for distress signals, /911e, clinic reception pages and bed-request alerts, because those do not go through dispatch. Only the automatic down and death alerts depend on it entirely.

Alerts are sent with the code 10-52 (or 911 for /911e), a heart-pulse icon, and a job list containing every enabled EMS department name plus the extra jobs configured under Dispatch.