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
F5Cfg.Framework = { mode = 'auto' } -- 'auto' | 'esx' | 'qb' | 'qbx' | 'custom'
With mode = 'auto', the first started resource wins, in this priority:
| Priority | Framework | Detected resource |
|---|---|---|
| 1 | QBox Core | qbx_core |
| 2 | QBCore | qb-core |
| 3 | ESX | es_extended |
Force a specific adapter by setting mode to 'esx', 'qb' or 'qbx', or 'custom' for a fork (see Custom framework).
Inventories
F5Cfg.Framework = { inventory = 'auto' }
With inventory = 'auto', detection runs in this priority:
| Priority | Inventory | Detected resource | Item image path (nui://…) |
|---|---|---|---|
| 1 | ox_inventory | ox_inventory | ox_inventory/web/images/%s.png |
| 2 | qs-inventory | qs-inventory | qs-inventory/html/images/%s.png |
| 3 | ps-inventory | ps-inventory | ps-inventory/html/images/%s.png |
| 4 | codem-inventory | codem-inventory | codem-inventory/html/itemimages/%s.png |
| 5 | tgiann-inventory | tgiann-inventory | inventory_images/images/%s.webp |
| 6 | qb-inventory | qb-inventory | qb-inventory/html/images/%s.png |
| 7 | ESX 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:
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:
{ id = 'cash', label = 'Cash', icon = 'fa-solid fa-money-bill-wave', accounts = { qb = 'cash', qbx = 'cash', esx = 'money' } },
Default active accounts per framework:
Currency id | QBCore | QBox | ESX |
|---|---|---|---|
cash | cash | cash | money |
bank | bank | bank | bank |
crypto | crypto | crypto | — |
blackmoney | — | — | black_money |
Rules the bridge applies at startup:
- A type with no account for the running framework is skipped (e.g.
cryptoon ESX,blackmoneyon QB/QBox). - Type
ids must be alphanumeric +_/-, and account keys must be alphanumeric, or the type is dropped with a debug warning. payoutTypemust resolve to an active type; if not, it falls back tobank, 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
F5Cfg.Framework = {
notify = 'auto', -- 'auto' | 'framework' | 'oxlib'
notifyStyle = 'custom', -- 'custom' | 'native'
}
| Option | Value | Behaviour |
|---|---|---|
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.
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
},
}
| Field | Purpose |
|---|---|
base | Required. The framework your fork derives from — 'qb', 'qbx' or 'esx'. Invalid/missing → resource inert |
getCore | Returns your core object |
playerLoadedEvent / playerUnloadEvent | Renamed 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 / uidColumn | DB 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.
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 = ... }, ... }
},
}
| Callback | Purpose |
|---|---|
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:
| Column | Notes |
|---|---|
code | The code string |
reward_type | ENUM('money','item','both') |
money | Legacy single money amount |
moneys | JSON — multi-account money list |
items | JSON — item list |
max_uses / uses | Usage cap and current count |
expiry | DATETIME, nullable |
is_private | 0 public / 1 private |
target_citizenid / target_citizenids | Legacy single target / JSON multi-target list |
created_by / creator_name / creator_steam | Who created the code |
deleted | Soft-delete flag |
code_active | Generated 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
- Configuration → Framework & Compatibility
- Configuration → Money & Currencies
- Features — how rewards and scopes use these systems
- Installation — start order and detection output