ox_core Structure and API
ox_core exposes a single Ox table of server functions plus class instances for
players, vehicles and accounts. There is no shared core object to fetch and no
event handshake.
Importing ox_core
Lua
Add the init file to your fxmanifest.lua:
shared_script '@ox_core/lib/init.lua'Or use ox_lib’s require if you prefer an explicit import:
local Ox = require '@ox_core.lib.init'TypeScript
bun i @overextended/ox_coreThe npm package ships full type definitions, so the whole API is discoverable from your editor.
The data model
This is where ox_core diverges most from QBCore and ESX.
| Concept | ox_core | QBCore / ESX equivalent |
|---|---|---|
userId | The person behind the account | No direct equivalent |
charId | One character owned by a user | citizenid / identifier |
stateId | Public-facing character identifier | — |
| Group | Membership with grades and permissions | Job, gang and society combined |
| Account | An object with an owner, roles and invoices | money.bank / accounts |
| Licence | An entity granted to a character | A boolean in metadata |
Separating user from character is the change that matters most in practice. A
ban, a Discord link or a donator perk attaches to the userId and survives
character deletion — something the other frameworks have to work around.
The player object
local player = Ox.GetPlayer(source)
player.charId -- number
player.userId -- number
player.stateId -- string
player.identifier -- string
player.source -- number
player.ped -- number
player.username -- stringPlayer methods are called on the instance:
player.addLicense('driver')
player.addStatus('hunger', 10)
player.setGroup('police', 2)
player.save()Server functions
-- Players
local player = Ox.GetPlayer(source)
local player = Ox.GetPlayerFromCharId(charId)
local player = Ox.GetPlayerFromUserId(userId)
local players = Ox.GetPlayers()
-- Groups
Ox.CreateGroup({ name = 'police', label = 'Police', grades = { { label = 'Officer' } } })
Ox.SetGroupPermission('police', 1, 'arrest', 'allow')
local members = Ox.GetGroupActivePlayers('police')
-- Accounts
local account = Ox.CreateAccount(charId, 'Savings')
local account = Ox.GetCharacterAccount(charId)
local account = Ox.GetGroupAccount('police')
-- Vehicles
local vehicle = Ox.CreateVehicle({ model = 'sultan', owner = charId }, coords, heading)
local vehicle = Ox.GetVehicleFromVin(vin)
Ox.SaveAllVehicles()
-- Moderation
Ox.BanUser(userId, banData)
local banned = Ox.IsUserBanned(userId)Events
| Event | Fires when |
|---|---|
ox:playerLoaded | A character finishes loading |
ox:playerLogout | A character logs out |
ox:createdCharacter | A new character is registered |
ox:deletedCharacter | A character is deleted |
ox:setGroup | A player’s group membership changes |
ox:setActiveGroup | A player switches their active group |
ox:licenseAdded / ox:licenseRemoved | A licence changes |
ox:updatedBalance | An account balance changes |
ox:transferredMoney | Money moves between accounts |
ox:spawnedVehicle / ox:despawnVehicle | A persisted vehicle appears or is stored |
ox:invoicePaid | An invoice is settled |
As with every framework, never trust a client-triggered event carrying money,
items or a group name. Resolve the player server-side with Ox.GetPlayer(source)
and validate there. See FiveM events.
Global states
ox_core publishes server state through statebags rather than callbacks, which is
why it needs OneSync. Player state such as isDead is readable directly from the
entity’s state bag on both sides.
Next steps
- ox_core installation
- ox_lib — the library the whole stack is built on
- Example resource →