The inventory never assumes which framework or script you run. It looks at what is started when it boots, and every framework- or script-specific piece lives in a small bridge file under client/custom/ and server/custom/ that you can read and edit.
money and black_money items, kept in sync with the accounts
cash item, kept in sync with the cash account
money item, kept in sync
Admins
groups admin and superadmin
permissions god and admin, or the command ace
same as QBCore
Starter items
StarterItems in server/custom/framework/esx.lua
qb-core's own
qb-core's own
On QBCore the inventory replaces the player's AddItem, RemoveItem, GetItemBySlot, GetItemByName, GetItemsByName, ClearInventory and SetInventory functions, so scripts using Player.Functions.AddItem keep working. On ESX, items registered as usable through ESX are picked up automatically.
Many scripts call another inventory directly. Inventory answers those calls itself, so they keep working without edits:
exports['qb-inventory']:AddItem, RemoveItem, HasItem, CanCarryItem, GetItemByName, GetItemsByName, GetItemBySlot, ClearInventory, SetInventory, OpenShop, CreateShop, CreateUsableItem, GetStashItems, AddItemIntoStash, RemoveItemIntoStash, OpenInventory (opens a stash), OpenInventoryById (opens another player) and the rest of the qb-inventory API are routed to qs-inventory. The real qb-inventory is stopped when Config.BypassQbInventory = true.
exports.ox_inventory:AddItem, RemoveItem, CanCarryItem, GetItem, Search, GetSlot, GetSlotWithItem, GetSlotsWithItem, SetMetadata, Items, GetCurrentWeapon, ClearInventory, RegisterShop and RegisterStash work on the server, and Search, Items, getCurrentWeapon and openInventory on the client. Items come back with ox-style and fields. , and are not supported and print a warning.
Scripts that only check GetResourceState('ox_inventory') will not see it as started. Remove that check or the ox_inventory dependency from those scripts — or, on Qbox, uncomment provide 'ox_inventory' in qs-inventory/fxmanifest.lua.
The inventory checks what the character wears every second or so and turns it into clothing items. While a player is inside a clothing shop menu, pause that check so trying clothes on does not create items; resume it when the menu closes:
lua
-- when your clothing menu opens
exports['qs-inventory']:setInClothing(true)
-- when it closes
exports['qs-inventory']:setInClothing(false)
Most paid clothing scripts already include these two calls. When the inventory closes, the outfit is saved through the detected appearance resource:
The event form gives you full control over the id:
lua
local stashId = 'locker_' .. lockerId
TriggerServerEvent('inventory:server:OpenInventory', 'stash', stashId, { maxweight = 100000, slots = 50 }, nil, 'Locker')
TriggerEvent('inventory:client:SetCurrentStash', stashId) -- so it saves and unlocks on close
For a personal stash, include the player's identifier in the id. Items can be put in or taken out of a stash without opening it with AddItemIntoStash and RemoveItemIntoStash on the server. Jobs Creator (jaksam) stashes, safes and armories are mapped to qs-inventory stashes automatically.
Create shops on the server and open them for a player:
lua
exports['qs-inventory']:CreateShop({
name = 'police_armory',
label = 'LSPD Armory',
coords = vec3(452.3, -980.0, 30.7), -- optional: player must be within 5 m
account = 'bank', -- 'money' (cash) or 'bank'
groups = { police = 0 }, -- optional: job and minimum grade
items = {
{ name = 'weapon_pistol', price = 500, amount = 10 },
{ name = 'pistol_ammo', price = 50, amount = 100 },
},
})
exports['qs-inventory']:OpenShop(source, 'police_armory')
A client can open a registered shop with TriggerServerEvent('inventory:openShop', 'police_armory'). With Config.DisableShopGenerationOnClient = true, shops can only be built on the server like this, which stops modified clients from inventing their own prices. For ready-made shops on the map with stock and deliveries, use qs-shops — see Shops and Add-ons.
Open another player's inventory, limited to one section if you like:
lua
-- client
TriggerServerEvent('inventory:server:OpenInventory', 'otherplayer', targetServerId, {
type = 'all', -- 'all', 'hotbar' or 'wallet'
})
hotbar shows only the five quick slots, wallet only cards, IDs and cash, all everything. Items in Config.notStolenItems cannot be taken, and the protected slot is only visible to the jobs in Config.PoliceJobs while Config.PoliceCanSeeSixthSlot is on. Without a framework police script, /searchplayer and the inventory:client:search event search the nearest player with hands up.
Then trigger the inventory's event once the character has been created — in esx_identity/client/main.lua, inside the register NUI callback, after the success notification:
Every move between inventories goes through the server: it checks the slots, the amounts, the weight, the items that cannot be stored and whether the player really has that second inventory open. Negative amounts are rejected and reported to the exploit webhook. Config.DisableShopGenerationOnClient = true makes shops server-only, and inv_busy locks the inventory while a progress bar or another action is running to prevent duplication.
The language is Config.Language, read from the qs:locale convar, so setr qs:locale "es" in server.cfg switches every Quasar resource at once. Translations are JSON files in locales/, and any key missing from a translation falls back to English. To add one, copy en.json to a new code, translate the values and set that code as the language.