Frameworks
SL-Marketplace runs on ESX Legacy, QBCore and Qbox from the same files. On start it detects which framework your server uses and from then on talks to it with that framework’s own functions and events. You do not need a different download per framework.
Supported setups
Section titled “Supported setups”| Framework | Resource | Player ID | Cash | Inventories | Owned vehicles |
|---|---|---|---|---|---|
| ESX Legacy | es_extended |
identifier |
money account |
ox_inventory or native ESX inventory |
owned_vehicles |
| QBCore | qb-core |
citizenid |
cash |
ox_inventory or qb-inventory |
player_vehicles |
| Qbox | qbx_core |
citizenid |
cash |
ox_inventory (required by Qbox) |
player_vehicles |
oxmysql and screenshot-basic are required on all three.
Detection
Section titled “Detection”Config.Framework = 'auto' -- 'auto', 'esx', 'qb' or 'qbx'With 'auto', the resource looks for a running qbx_core, then qb-core, then es_extended, and uses the first one it finds. Qbox is checked first because it ships a compatibility layer that also answers as qb-core.
The result is printed when the resource starts:
[sl-marketplace] Framework: qbx[marketplace] Inventory backend: oxDetection happens once, when sl-marketplace starts, so your framework must be ensured before it in server.cfg:
ensure oxmysqlensure screenshot-basicensure qbx_core # or es_extended / qb-core, plus your inventoryensure sl-marketplaceIf the console shows No framework detected, the marketplace started too early. Fix the order, or set Config.Framework explicitly.
Inventory backends
Section titled “Inventory backends”Config.InventoryBackend = 'auto' -- 'auto', 'ox_inventory', 'esx' or 'qb-inventory'With 'auto', ox_inventory is used whenever it is running, on any framework. Otherwise the framework’s own inventory is used: the native ESX inventory on ESX, qb-inventory on QBCore. Qbox always needs ox_inventory.
ox_inventory and qb-inventory are slot-based: when a seller lists an item, the marketplace takes exactly the slot they picked and keeps its metadata (weapon serial, ammo, durability…). The buyer receives that same item with that same metadata. With the native ESX inventory, weapons come from the player’s loadout, with their ammo and components.
Item icons come from ox_inventory or qb-inventory automatically; see Config.ItemIcons.
Vehicles
Section titled “Vehicles”Players can list the vehicles they own. While a vehicle is listed, the marketplace holds it: it disappears from the seller’s garage and goes to the buyer when sold. If the seller cancels the listing it goes straight back to them; if the listing expires, it waits in their mailbox.
| Framework | While listed | When delivered |
|---|---|---|
| ESX | owned_vehicles.owner becomes marketplace |
owner becomes the new owner’s identifier |
| QBCore / Qbox | player_vehicles.citizenid and license are left empty |
citizenid and license are set to the new owner’s |
On QBCore and Qbox the vehicle cannot be given a marketplace owner, because player_vehicles.citizenid has a foreign key to players. The marketplace remembers the seller in its own listing instead.
The framework bridge
Section titled “The framework bridge”Everything framework-specific lives in bridge/. The rest of the script never calls ESX, QBCore or Qbox directly: it calls Framework.*, and the adapter for the detected framework translates it.
bridge/ framework.lua detection (Config.Framework) callback/server.lua client → server callbacks callback/client.lua server/esx.lua server adapter for each framework server/qb.lua server/qbx.lua client/esx.lua client adapter for each framework client/qb.lua client/qbx.luaEach adapter starts with a check such as if Framework.Name ~= 'qb' then return end, so only the one for your framework runs. The adapters ship unencrypted: you can edit them if your framework is modified.
Server functions
Section titled “Server functions”| Function | Returns |
|---|---|
Framework.Name |
'esx', 'qb' or 'qbx' |
Framework.GetPlayer(source) |
{ source, identifier, job = { name, grade } } or nil |
Framework.GetIdentifier(source) |
The player’s identifier (identifier or citizenid) |
Framework.GetSourceByIdentifier(identifier) |
The player’s server ID if online, or nil |
Framework.GetMoney(source) |
Cash on hand |
Framework.RemoveMoney(source, amount) |
true if the player had enough and it was removed |
Framework.AddMoney(source, amount) |
true if it was added |
Framework.Notify(source, message, type) |
Shows a framework notification ('info', 'success', 'error', 'warning') |
Framework.OnPlayerLoaded(cb) |
Calls cb(source) when a character finishes loading |
Framework.GetOwnedVehicles(identifier) |
List of { plate, model, data } |
Framework.OwnsVehicle(identifier, plate) |
true or false |
Framework.SetVehicleOwner(plate, from, to) |
Moves a vehicle between owners; 'marketplace' means held by the marketplace |
Framework.GetItemNames() |
Item names from the framework’s catalogue, for automatic categories |
Framework.GetPlayer returns the same shape on every framework, so your own code in server/handlers.lua can use it without caring which framework is running:
Handlers.CanCreateListing = function(data) if data.category == 'weapons' then local player = Framework.GetPlayer(data.actorSource) if not player or player.job.name ~= 'police' then return false, 'Only the police can sell weapons here' end end return trueendClient functions
Section titled “Client functions”| Function | What it does |
|---|---|
Framework.Notify(message, type) |
Shows a framework notification |
Framework.IsPlayerLoaded() |
true once the character is loaded |
Framework.OnPlayerLoaded(cb) |
Calls cb() when the character loads |
Framework.OnPlayerUnloaded(cb) |
Calls cb() on logout or character switch |
Events the adapters listen to
Section titled “Events the adapters listen to”| Framework | Character loaded | Logout |
|---|---|---|
| ESX | esx:playerLoaded |
esx:onPlayerLogout |
| QBCore / Qbox | QBCore:Server:PlayerLoaded, QBCore:Client:OnPlayerLoaded |
QBCore:Client:OnPlayerUnload |
If your multicharacter fires different events, change them in the adapter.
Callbacks
Section titled “Callbacks”Client → server requests use the marketplace’s own callback system (Callback.Register on the server, Callback.Trigger on the client), not the framework’s. It behaves the same on all three frameworks and needs no extra dependency such as ox_lib.
Adapting to a modified framework
Section titled “Adapting to a modified framework”- Find the adapter for your framework in
bridge/server/andbridge/client/. - Change only the body of the functions you need: for example, a different cash account, or a renamed export.
- Keep the function names and what they return: the rest of the script relies on them.
- Restart the resource and check the console for the
Framework:andInventory backend:lines.
Keep a copy of your changes: an update replaces the files in bridge/ just like any other part of the resource.