FiveM Docs
Guides

Money and Accounts

How money works in ESX Legacy, covering cash, bank and black_money accounts, xPlayer account methods, starting money, paychecks, society money and custom accounts.

ESX Legacy stores a player's money in accounts: money (cash), bank and black_money by default. On the server you read and change them through the xPlayer object, for example xPlayer.addAccountMoney('bank', 500, 'Job reward'), and you configure which accounts exist and how much new players start with in es_extended/shared/config/main.lua.

Overview

AccountMeaningNotes
moneyCash on handShortcut methods getMoney, addMoney, removeMoney, setMoney
bankBank balancetransferable = false, receives paychecks
black_moneyDirty moneyUsed by drug and money-wash scripts

Accounts are saved as JSON in the users.accounts column, for example {"bank":50000,"money":0,"black_money":0}. ESX saves players every 10 minutes and when they disconnect. Only the server can change money; clients receive updates through the esx:setAccountMoney event.

Configure accounts

es_extended/shared/config/main.lua
Config.Accounts = {
    bank = {
        label = TranslateCap("account_bank"),
        round = true,
        transferable = false,
    },
    black_money = {
        label = TranslateCap("account_black_money"),
        round = true,
    },
    money = {
        label = TranslateCap("account_money"),
        round = true,
    },
}

Config.StartingAccountMoney = { bank = 50000 }
KeyTypeDescription
labelstringDisplay name. The defaults are translated through the locale files.
roundbooleanRound amounts to whole numbers. Defaults to true when omitted.
transferablebooleanfalse stops players from giving or dropping this account through the default inventory. Defaults to transferable.

Change the starting money

Config.StartingAccountMoney is used when a character is created, and as the fallback value for any account a loading player does not have yet. New players get no cash by default. To give them some:

es_extended/shared/config/main.lua
Config.StartingAccountMoney = { money = 500, bank = 5000 }

Existing players are not affected unless the account is new to them.

Read and change money (server)

All account methods take the account name as a string. Amounts must be numbers.

xPlayer.getAccount(accountName)                      -- { name, money, label, round, index } or nil
xPlayer.getAccounts(minimal)                         -- list, or { name = money } when minimal is true
xPlayer.addAccountMoney(accountName, money, reason)  -- true on success
xPlayer.removeAccountMoney(accountName, money, reason)
xPlayer.setAccountMoney(accountName, money, reason)
xPlayer.getMoney() / addMoney(money, reason) / removeMoney(money, reason) / setMoney(money)
NameTypeDescription
accountNamestringmoney, bank, black_money or a custom account. Case-insensitive lookup.
moneynumberAmount. Must be greater than 0 for add/remove, at least 0 for set.
reasonstring?Free text passed to the money events, useful for logging.

Return values and errors

  • removeAccountMoney returns false when the balance would go negative or when rounding turns the amount into 0. It never allows negative balances.
  • addAccountMoney returns false if the new balance would overflow.
  • An unknown account name, a non-number amount, or an amount of 0 or less raises a Lua error with the default inventory. Validate input first, especially values that came from a client.

Example: a safe purchase

server/main.lua
ESX = exports['es_extended']:getSharedObject()

local PRICE <const> = 250

RegisterNetEvent('coffee:buy', function()
    local xPlayer = ESX.GetPlayerFromId(source)
    if not xPlayer then return end

    -- Price is decided on the server, never sent by the client
    if not xPlayer.removeAccountMoney('money', PRICE, 'Coffee shop') then
        return xPlayer.showNotification('Not enough cash')
    end

    xPlayer.addInventoryItem('coffee', 1)
end)

Removing the money first and checking the boolean is enough to prevent the classic "buy with no money" exploit. Do not trust a price, account or amount sent by the client; see Callbacks for validating client input.

Example: pay from bank, fall back to cash

server/main.lua
local function charge(xPlayer, amount, reason)
    if xPlayer.removeAccountMoney('bank', amount, reason) then
        return 'bank'
    end
    if xPlayer.removeAccountMoney('money', amount, reason) then
        return 'money'
    end
    return nil
end

Read money on the client

The client gets a copy of the accounts in ESX.PlayerData.accounts. Use it for display only.

client/main.lua
local bank = ESX.GetAccount('bank')
if bank then
    print(('Bank balance: $%s'):format(ESX.Math.GroupDigits(bank.money)))
end

RegisterNetEvent('esx:setAccountMoney', function(account)
    print(('%s is now %s'):format(account.name, account.money))
end)

Money events

EventSideArguments
esx:addAccountMoneyServersource, accountName, money, reason
esx:removeAccountMoneyServersource, accountName, money, reason
esx:setAccountMoneyServersource, accountName, money, reason
esx:setAccountMoneyClientaccount (the full account table)

A simple server-side money log:

server/logs.lua
AddEventHandler('esx:removeAccountMoney', function(playerId, accountName, amount, reason)
    if amount >= 100000 then
        print(('[money] %s removed %s from %s (%s)'):format(playerId, amount, accountName, reason))
    end
end)

Add a custom account

Add the account to Config.Accounts

es_extended/shared/config/main.lua
Config.Accounts = {
    bank = { label = TranslateCap("account_bank"), round = true, transferable = false },
    black_money = { label = TranslateCap("account_black_money"), round = true },
    money = { label = TranslateCap("account_money"), round = true },
    crypto = { label = "Crypto", round = false, transferable = false },
}

Use a plain string label unless you also add a locale key.

Optionally give a starting balance

es_extended/shared/config/main.lua
Config.StartingAccountMoney = { bank = 50000, crypto = 0 }

Restart the server

When players load, ESX builds their account list from Config.Accounts. Existing players get the new account with the starting value (or 0), and it is saved into users.accounts on the next save. Now xPlayer.addAccountMoney('crypto', 0.25, 'Mining') works, and /giveaccountmoney accepts crypto.

ox_inventory

With ox_inventory, accounts listed in the inventory:accounts convar (default ["money", "black_money"]) are stored as items in the ox inventory, not in users.accounts. ESX routes the account methods to ox_inventory and returns false instead of raising an error on invalid input. Only add a custom account to that convar if it should be a physical item. See ox_inventory.

Paychecks

Salaries come from the player's job grade (job_grades.salary) and are paid into bank.

Config keyDefaultDescription
Config.EnablePaychecktrueTurn paychecks on or off
Config.PaycheckInterval7 * 60000Interval in milliseconds
Config.OffDutyPaycheckMultiplier0.5Off-duty players get this share of their salary
Config.EnableSocietyPayoutsfalsePay salaries from the job's society account (needs esx_society)
Config.LogPaycheckfalseLog paychecks to Discord
Config.PaycheckBatchSize, PaycheckBatchDelay, PaycheckJitter100, 250, 30000Spread payouts on big servers

With society payouts enabled, a player whose company cannot cover the salary gets a "company has no money" notification and is not paid. Jobs without a registered society are paid normally. xPlayer.togglePaycheck(false) pauses paychecks for one player.

Society (company) money

Company money lives in esx_addonaccount shared accounts named society_<job>, not on the player. Use the GetSharedAccount export on the server:

server/main.lua
local account = exports.esx_addonaccount:GetSharedAccount('society_police')
if account then
    account.addMoney(5000)
    print(('Police funds: %s'):format(account.money))
end

The account object has addMoney, removeMoney and setMoney. Setup is described in Create a job and on the esx_addonaccount page.

Common issues

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