F5 StudioF5 Studio
Skip to main content

Framework Compatibility

F5 Redeem Code runs on a self-detecting bridge. At startup it resolves a framework and an inventory, wires up money accounts, and picks a notification backend — all from F5Cfg.Framework and F5Cfg.Inventory.

If detection fails, the resource logs an error and goes inert (commands still register, but redeeming/admin do nothing) rather than throwing.

Frameworks

config/config.lua
F5Cfg.Framework = { mode = 'auto' }   -- 'auto' | 'esx' | 'qb' | 'qbx' | 'custom'

With mode = 'auto', the first started resource wins, in this priority:

PriorityFrameworkDetected resource
1QBox Coreqbx_core
2QBCoreqb-core
3ESXes_extended

Force a specific adapter by setting mode to 'esx', 'qb' or 'qbx', or 'custom' for a fork (see Custom framework).

Inventories

config/config.lua
F5Cfg.Framework = { inventory = 'auto' }

With inventory = 'auto', detection runs in this priority:

PriorityInventoryDetected resourceItem image path (nui://…)
1ox_inventoryox_inventoryox_inventory/web/images/%s.png
2qs-inventoryqs-inventoryqs-inventory/html/images/%s.png
3ps-inventoryps-inventoryps-inventory/html/images/%s.png
4codem-inventorycodem-inventorycodem-inventory/html/itemimages/%s.png
5tgiann-inventorytgiann-inventoryinventory_images/images/%s.webp
6qb-inventoryqb-inventoryqb-inventory/html/images/%s.png
7ESX native(fallback when framework is ESX)(no image path)

Force one with inventory = 'ox' | 'qb' | 'qs' | 'ps' | 'codem' | 'tgiann' | 'esx_native' | 'custom'.

The image path is used to render item icons in the redeem result and the admin console. Override it globally with:

config/config.lua
F5Cfg.Inventory = {
imageUrl = 'auto', -- or 'nui://my-inventory/images/%s.png'
}

%s is replaced with the item name. Leave it 'auto' to use the detected inventory's path.

Money & Currencies

Each entry in F5Cfg.Money.types maps an internal id to a native account key per framework:

config/config.lua
{ id = 'cash', label = 'Cash', icon = 'fa-solid fa-money-bill-wave', accounts = { qb = 'cash', qbx = 'cash', esx = 'money' } },

Default active accounts per framework:

Currency idQBCoreQBoxESX
cashcashcashmoney
bankbankbankbank
cryptocryptocrypto
blackmoneyblack_money

Rules the bridge applies at startup:

  • A type with no account for the running framework is skipped (e.g. crypto on ESX, blackmoney on QB/QBox).
  • Type ids must be alphanumeric + _/-, and account keys must be alphanumeric, or the type is dropped with a debug warning.
  • payoutType must resolve to an active type; if not, it falls back to bank, then to the first active type.

The active list is exactly what admins see as per-account money inputs when creating a code, and codes can pay several of them in a single redeem. See Features → Money.

Notifications

config/config.lua
F5Cfg.Framework = {
notify = 'auto', -- 'auto' | 'framework' | 'oxlib'
notifyStyle = 'custom', -- 'custom' | 'native'
}
OptionValueBehaviour
notify'auto'Use ox_lib notifications when it's present, otherwise the framework's native notify
notify'framework'Always use the framework's native notify
notify'oxlib'Always use ox_lib
notifyStyle'custom'Show this resource's styled in-NUI toasts (the notify backend is not used for these)
notifyStyle'native'Hand messages to the notify backend instead of the NUI toasts

Custom framework

For a fork of QB / QBox / ESX, set mode = 'custom' and describe only what your fork renamed. Any field left nil inherits the base behaviour — most forks need just base + getCore.

config/config.lua
F5Cfg.Framework = {
mode = 'custom',
custom = {
base = 'qb', -- REQUIRED: 'qb' | 'qbx' | 'esx'
getCore = nil, -- function() return exports['my-core']:GetCoreObject() end

playerLoadedEvent = nil, -- renamed load event (same args as base)
playerUnloadEvent = nil, -- renamed unload event
-- ... advanced overrides below
},
}
FieldPurpose
baseRequired. The framework your fork derives from — 'qb', 'qbx' or 'esx'. Invalid/missing → resource inert
getCoreReturns your core object
playerLoadedEvent / playerUnloadEventRenamed load/unload events (same args as the base)
normalize(raw)Normalize a raw player object
getPlayer(src) / getPlayerByUid(uid) / getPlayers()Player lookups
identifierOf(raw)Extract the Citizen ID from a raw player
getAccount(raw,key) / addAccount(raw,key,amt,reason) / removeAccount(raw,key,amt,reason)Money account access
hasGroup(src,group)Admin group check
onPlayerLoaded(emit) / onPlayerUnload(emit)Custom load/unload wiring — call emit(src, uid) when the args differ from the base
playersTable / uidColumnDB table + column holding Citizen IDs, for private-code target validation. Defaults from base: QB/QBox → players.citizenid, ESX → users.identifier
notify(msg,kind,duration)Client notify override
getPlayerData()Client player data → { uid, name, charinfo, job, raw }

Custom inventory

Set Framework.inventory = 'custom' and provide every callback. Any callback left nil logs an error and that feature degrades.

config/config.lua
F5Cfg.Inventory = {
custom = {
-- addItem(src,name,amount,metadata) removeItem(src,name,amount,slot)
-- hasItem(src,name,amount) canCarryItem(src,name,amount)
-- getItemLabel(name) getItemImage(name)
-- getAllItems() -> { { name = ..., label = ... }, ... }
},
}
CallbackPurpose
addItem(src, name, amount, metadata)Give an item — used when granting item rewards
removeItem(src, name, amount, slot)Remove an item
hasItem(src, name, amount)Check possession
canCarryItem(src, name, amount)Inventory-space pre-check before granting
getItemLabel(name)Human label for display
getItemImage(name)Icon path for display
getAllItems()Full item catalogue for the admin item picker

Database schema

The script uses two InnoDB tables (utf8mb4), created and migrated automatically when autoCreateTables is true:

f5_codes

Holds every code. Key columns:

ColumnNotes
codeThe code string
reward_typeENUM('money','item','both')
moneyLegacy single money amount
moneysJSON — multi-account money list
itemsJSON — item list
max_uses / usesUsage cap and current count
expiryDATETIME, nullable
is_private0 public / 1 private
target_citizenid / target_citizenidsLegacy single target / JSON multi-target list
created_by / creator_name / creator_steamWho created the code
deletedSoft-delete flag
code_activeGenerated column = code while live, NULL when deleted

The unique key uk_code_active is on code_active, so only live codes must have unique names — a deleted code frees its name for re-creation. This generated column needs MySQL 5.7+ / MariaDB 10.2+; on older servers the migration is skipped and the legacy uk_code unique key is kept.

f5_code_redemptions

One row per successful redemption — code_id, code, citizenid, steam, player_name, money, moneys (JSON), items (JSON) and redeemed_at. This is the source of the once-per-player rule and the admin History tab.

See Also