FiveM Docs
Addons

esx_addonaccount

esx_addonaccount stores extra money accounts such as society funds in ESX Legacy. Covers SQL setup, the account object, exports, events and pitfalls.

esx_addonaccount is a server-only library resource that stores money outside of the normal player accounts. Use it whenever money belongs to a job, a business or a property instead of a player's wallet, for example society funds used by esx_society and esx_billing.

Overview

Resourceesx_addonaccount (version 1.1)
SideServer only
Dependenciesesx_lib, es_extended, oxmysql
SQL fileesx_addonaccount.sql
ExportsGetAccount, GetSharedAccount, AddSharedAccount

There are two kinds of accounts, controlled by the shared column of the addon_account table:

  • Shared (shared = 1): a single account without an owner. Typical for society_<job> accounts.
  • Personal (shared = 0): one account per player identifier. The resource creates the row automatically when a player loads (esx:playerLoaded) and stores the loaded accounts on the player as xPlayer.get('addonAccounts').

Installation

Import the SQL

Run esx_addonaccount.sql against your ESX database. It creates addon_account (the definitions) and addon_account_data (the balances). Both tables must use InnoDB.

Ensure the resource

Start it after es_extended and before every resource that uses it:

server.cfg
ensure oxmysql
ensure esx_lib
ensure es_extended
ensure esx_addonaccount
ensure esx_society
ensure esx_billing

Define your accounts

Insert one row per account. Shared accounts get their balance row on startup automatically.

INSERT INTO `addon_account` (`name`, `label`, `shared`) VALUES
  ('society_mechanic', 'Mechanic', 1),
  ('property_black_money', 'Black money (property)', 0);

On startup the resource runs a schema migration. It adds a generated owner_key column and a unique key on (account_name, owner_key) if they are missing. The migration aborts (and disables all accounts) instead of changing data when it finds problems:

  • addon_account_data is not InnoDB
  • rows with account_name IS NULL or owner = ''
  • duplicate rows for the same account and owner

Configuration

esx_addonaccount has no config.lua. Everything is driven by the addon_account table.

ColumnTypeDescription
nameVARCHAR(60)Unique account name, e.g. society_police
labelVARCHAR(100)Display label (stored, not used by this resource)
sharedINT1 = shared account, 0 = one account per player

Server exports

GetSharedAccount

exports.esx_addonaccount:GetSharedAccount(name)
NameTypeDescription
namestringAccount name from addon_account

Returns the account object or nil if the account does not exist or the resource is not ready yet.

server/main.lua
local account = exports.esx_addonaccount:GetSharedAccount('society_mechanic')

if account and account.addMoney(2500) then
    print(('Mechanic society now has $%s'):format(account.money))
end

GetAccount

exports.esx_addonaccount:GetAccount(name, owner)
NameTypeDescription
namestringName of a non-shared account
ownerstringPlayer identifier (xPlayer.identifier)

Returns the personal account object or nil. Accounts are only kept in memory for loaded players (offline accounts are evicted about once a minute after they are saved), so call this for online players.

server/main.lua
local xPlayer = ESX.GetPlayerFromId(source)
local stash = exports.esx_addonaccount:GetAccount('property_black_money', xPlayer.identifier)

if stash then
    stash.removeMoney(1000)
end

AddSharedAccount

exports.esx_addonaccount:AddSharedAccount(society, amount)
NameTypeDescription
societytable{ name = string, label = string }
amountnumber?Starting balance, defaults to 0

Creates a shared account at runtime (inserts into both tables) and returns it. If the account already exists, the existing object is returned and nothing is inserted. Returns nil on invalid input or a failed insert.

server/main.lua
exports.esx_addonaccount:AddSharedAccount({ name = 'society_bahama', label = 'Bahama Mamas' }, 10000)

Account object

Field / methodDescription
nameAccount name
ownerIdentifier, or nil for shared accounts
moneyCurrent balance
addMoney(amount)Adds money. Returns true or false
removeMoney(amount)Removes money. Returns false if the balance would drop below 0
setMoney(amount)Sets the balance. Returns true or false
save(cb?)Forces a write. cb(success) runs once the value is persisted
isDirty()true while a change has not been written yet
withPersistence(action)Runs action(money) while holding the persistence lock. Return success, delta to apply a change atomically

amount must be a whole number between 0 and 2147483647. Floats, negative numbers and NaN are rejected and the method returns false. Every successful change is saved to the database right away (with automatic retry every 5 seconds on failure).

Events

All events are local server events. Clients cannot trigger them.

EventArgumentsWhen
esx_addonaccount:getSharedAccountname, cbLegacy getter. cb(account)
esx_addonaccount:getAccountname, owner, cbLegacy getter. cb(account)
esx_addonaccount:addMoneyname, amount, ownerFired after addMoney succeeded
esx_addonaccount:removeMoneyname, amount, ownerFired after removeMoney succeeded
esx_addonaccount:setMoneyname, amount, ownerFired after setMoney succeeded
esx_addonaccount:refreshAccountsnoneReloads account definitions from the database

Listening for changes is useful for logging:

server/logs.lua
AddEventHandler('esx_addonaccount:removeMoney', function(name, amount, owner)
    if name:find('^society_') then
        print(('[audit] %s lost $%s'):format(name, amount))
    end
end)

The getter events still work, but the exports are simpler and avoid callback nesting:

TriggerEvent('esx_addonaccount:getSharedAccount', 'society_police', function(account)
    if account then account.addMoney(500) end
end)

Integration tips

  • Society accounts follow the society_<job name> pattern. esx_society and esx_billing rely on that naming.
  • Store item stashes in esx_addoninventory and generic key/value data in esx_datastore.
  • New rows in addon_account are picked up without a restart when ESX fires esx:sqlCatalogReady for that table, or when you trigger esx_addonaccount:refreshAccounts on the server.

Common issues

  • addMoney returns false: you passed a float (for example a percentage cut like price * 0.15). Round first with math.floor.
  • Console says "Duplicate addon accounts" or "Invalid account_name/empty owner": the migration stopped on purpose. Clean up the listed rows in addon_account_data by hand, then restart the resource.
  • Account is nil right after a server start: another resource asked before esx_addonaccount finished loading. Check for nil and retry, or make sure the dependent resource starts later.

Frequently asked questions

Independent documentation

esx-fivem.com is a community project and is not affiliated with the ESX Framework team. Facts on this page were checked against the upstream source. Official resources: docs.esx-framework.org and github.com/esx-framework.
Edit on GitHub

Last updated on

On this page