Skip to main content

BenzyMoney — Exports

Every export other resources can call, each with a ready-to-paste example. All money logic is server-authoritative and runs through the same validated engine, so the rules (positive whole amounts, sufficient funds, no overflow) always apply.

Identifiers

Anywhere an identifier is asked for, you may pass any of:

FormExampleNotes
Server id (number)source, 7Online players only.
License (string)'license:abc123...'Works for offline players too.
Account key (string)'government', 'lsac'The society's fixed key 'government', or a business's key from Config.Businesses. This is the key, not the display label — renaming an account (e.g. Config.GovernmentLabel) never changes it.
Database id (table){ id = 42 }The stable id from BenzyMoney's events/exports (for integrations). Offline ok.
Account number (table){ accountNumber = '48217390' }A player's account number (the one shown on the ATM / Personal tab). Offline ok.

Offline note: reading or changing an offline player can yield. Call those exports from inside a thread (CreateThread), an event handler, or a command — not from the top level of a file.

src vs identifier: most exports take an identifier (any form above). A few instead take a src — a connected player's server id specifically — because they check/act on a live player and do not accept a license or offline form: CanUseAccount, RespondToRequest, CancelRequest.

Mutators return two values: ok (boolean) and either the new balance (success) or an error code string (failure) — except the transfer-style exports (Pay, DepositCash, WithdrawCash, PayFromAccountToPlayer, PayPlayerToAccount, TransferBetweenAccounts), whose second value is nil on success. Error codes: INVALID_AMOUNT, MAX_TRANSACTION, OVERFLOW, INSUFFICIENT_FUNDS, NOT_FOUND, ACCOUNT_NOT_FOUND, INVALID_TARGET, STORAGE_NOT_READY, STORAGE_ERROR. Reads return the value, or nil if the target doesn’t exist. In the examples, source is the player a server event/command is acting on, and any other id (like targetId) is a placeholder you set yourself.


Server exports — reads

GetCash(identifier) → number (or nil). A player’s cash on hand.

local cash = exports.BenzyMoney:GetCash(source)

GetBank(identifier) → number (or nil). A player’s bank balance.

local bank = exports.BenzyMoney:GetBank(source)

GetTotal(identifier) → number (or nil). Cash + bank.

local total = exports.BenzyMoney:GetTotal(source)

GetBalances(identifier){ cash, bank, total } (or nil). All three at once.

local money = exports.BenzyMoney:GetBalances(source)
print(money.cash, money.bank, money.total)

GetPlayerData(identifier){ id, license, name, cash, bank, accountNumber } (or nil). Full record; works offline.

local data = exports.BenzyMoney:GetPlayerData(source)
if data then print(data.name, data.id, data.cash, data.bank) end

IsOnline(identifier) → boolean. Is this player currently connected?

local online = exports.BenzyMoney:IsOnline('license:abc123')

SearchPlayers(query, limit) → array of { id, license, name, cash, bank }. Fuzzy name search (includes offline players).

local matches = exports.BenzyMoney:SearchPlayers('john', 10)
for _, p in ipairs(matches) do print(p.name, p.license) end

GetAccountBalance(accountKey) → number (or nil). Balance of any shared account (government or a business).

local balance = exports.BenzyMoney:GetAccountBalance('lsac')

GetSocietyBalance() → number. The government/society account balance.

local gov = exports.BenzyMoney:GetSocietyBalance()

GetBusinessBalance(businessKey) → number (or nil). A business account balance.

local shopFunds = exports.BenzyMoney:GetBusinessBalance('lsac')

GetAllBusinesses() → array of { key, label, bank }. Every business account.

for _, b in ipairs(exports.BenzyMoney:GetAllBusinesses()) do
print(b.key, b.label, b.bank)
end

CanUseAccount(src, accountKey) → boolean. Does this player pass that account's access rule (by default, its ACE permission)?

if exports.BenzyMoney:CanUseAccount(source, 'government') then
-- this player is allowed to spend government funds
end

GetTransactions(identifierOrKey, limit) → array of transaction rows. Recent history for a player or an account. Each row's created_at is a Unix timestamp in seconds (consistent across database + file storage).

local history = exports.BenzyMoney:GetTransactions(source, 20)
for _, tx in ipairs(history) do print(tx.tx_type, tx.amount, tx.reason, os.date('%c', tx.created_at)) end

FormatMoney(amount) → string. Format a number with the configured currency symbol + separators.

local text = exports.BenzyMoney:FormatMoney(1234567) -- "$1,234,567"

GetCurrency() → string. The configured currency symbol.

local symbol = exports.BenzyMoney:GetCurrency() -- "$"

GetAccountNumber(identifier) → string (or nil). A player’s account number (works offline).

local number = exports.BenzyMoney:GetAccountNumber(source)

CanAfford(identifier, account, amount) → boolean. Does this player/account hold at least amount? (account = 'cash' or 'bank'; shared accounts use 'bank'.)

if exports.BenzyMoney:CanAfford(source, 'bank', 500) then
-- they can pay $500 from their bank
end

GetTopPlayers(limit) → array of { id, license, name, cash, bank, total }, richest first.

for _, p in ipairs(exports.BenzyMoney:GetTopPlayers(10)) do
print(p.name, p.total)
end

GetEconomyStats(){ players, playerCash, playerBank, playerTotal, government, business, total }. Total money in circulation.

local stats = exports.BenzyMoney:GetEconomyStats()
print('Money in the economy: ' .. exports.BenzyMoney:FormatMoney(stats.total))

Server exports — player mutators

Each takes an optional trailing reason shown in the Discord log + transaction history.

AddCash(identifier, amount, reason) — add cash to a player.

local ok, newCash = exports.BenzyMoney:AddCash(source, 500, 'Daily reward')

RemoveCash(identifier, amount, reason) — take cash (fails if they can’t afford it).

local ok, newCash = exports.BenzyMoney:RemoveCash(source, 100, 'Bus fare')
if not ok then print('Could not charge: ' .. newCash) end

SetCash(identifier, amount, reason) — set cash to an exact amount.

local ok = exports.BenzyMoney:SetCash(source, 0, 'Reset cash')

AddBank(identifier, amount, reason) — add to a player’s bank.

local ok, newBank = exports.BenzyMoney:AddBank(source, 1000, 'Paycheck')

RemoveBank(identifier, amount, reason) — take from a player’s bank.

local ok, newBank = exports.BenzyMoney:RemoveBank(source, 250, 'Rent')

SetBank(identifier, amount, reason) — set bank to an exact amount.

local ok = exports.BenzyMoney:SetBank(source, 5000, 'Admin set')

AddMoney(identifier, account, amount, reason) — add to 'cash' or 'bank'.

local ok, newBal = exports.BenzyMoney:AddMoney(source, 'cash', 300, 'Tip')

RemoveMoney(identifier, account, amount, reason) — remove from 'cash' or 'bank'.

local ok, newBal = exports.BenzyMoney:RemoveMoney(source, 'bank', 300, 'Fee')

SetMoney(identifier, account, amount, reason) — set 'cash' or 'bank' to an exact amount.

local ok = exports.BenzyMoney:SetMoney(source, 'cash', 100, 'Starter cash')

DepositCash(identifier, amount, reason) — move a player’s own cash into their bank.

local ok, err = exports.BenzyMoney:DepositCash(source, 500, 'Deposit')

WithdrawCash(identifier, amount, reason) — move a player’s own bank into cash.

local ok, err = exports.BenzyMoney:WithdrawCash(source, 500, 'Withdrawal')

Pay(fromIdentifier, toIdentifier, amount, fromAccount, toAccount, reason) — move money from one player to another (accounts default to 'bank').

local targetId = 2 -- the recipient's server id
local ok, err = exports.BenzyMoney:Pay(source, targetId, 500, 'bank', 'bank', 'Loan repayment')

RobCash(fromIdentifier, amount, toIdentifier?) → number stolen. Take up to amount of a player's cash (capped at what they actually have); optionally give it to toIdentifier. Returns how much was taken (0 if none). Fires BenzyMoney:CashRobbed.

-- A mugging script takes up to $500 from the victim and hands it to the robber
local stolen = exports.BenzyMoney:RobCash(victimId, 500, robberId)

Server exports — account mutators (government + businesses)

accountKey is the fixed key — 'government' for the society, or a business's key from Config.Businesses (e.g. 'lsac'). It is not the display label, so renaming an account (Config.GovernmentLabel or a business's label) never changes what you pass here.

AddToAccount(accountKey, amount, reason) — add to a shared account.

local ok, newBal = exports.BenzyMoney:AddToAccount('lsac', 1000, 'Insurance payout')

RemoveFromAccount(accountKey, amount, reason) — take from a shared account.

local ok, newBal = exports.BenzyMoney:RemoveFromAccount('lsac', 500, 'Supplies')

SetAccountBalance(accountKey, amount, reason) — set a shared account to an exact balance.

local ok = exports.BenzyMoney:SetAccountBalance('lsac', 0, 'Reset')

DepositToSociety(amount, reason) — add to the government account.

local ok = exports.BenzyMoney:DepositToSociety(250, 'Court fee')

WithdrawFromSociety(amount, reason) — take from the government account.

local ok, err = exports.BenzyMoney:WithdrawFromSociety(1000, 'Public works')

AddBusinessMoney(businessKey, amount, reason) — add to a business (logs to the business webhook).

local ok = exports.BenzyMoney:AddBusinessMoney('lsac', 750, 'Sale')

RemoveBusinessMoney(businessKey, amount, reason) — take from a business.

local ok, err = exports.BenzyMoney:RemoveBusinessMoney('lsac', 200, 'Refund')

PayFromAccountToPlayer(accountKey, toIdentifier, amount, reason) — pay a player out of an account (payroll/salary). Lands in the player's bank (accounts hold bank money only). To pay into cash instead, use RemoveFromAccount + AddCash.

local employeeId = 3
local ok, err = exports.BenzyMoney:PayFromAccountToPlayer('lsac', employeeId, 2000, 'Weekly pay')

PayPlayerToAccount(fromIdentifier, accountKey, amount, reason) — charge a player into an account (fines/fees). Comes out of the player's bank (accounts hold bank money only). Atomic: fails if they can't afford the full amount. To charge cash instead, use RemoveCash + AddToAccount.

local ok, err = exports.BenzyMoney:PayPlayerToAccount(source, 'government', 250, 'Speeding fine')

ChargeFine(identifier, amount, reason, accountKey?) → number charged. Like the above, but caps at the player's bank balance (so a partial fine still goes through, $0 if they're broke) and defaults the account to 'government'. Returns how much was actually taken. Ideal for fines/citations.

-- Fine $750 from bank -> government; takes whatever they have if they can't afford it all
local charged = exports.BenzyMoney:ChargeFine(playerId, 750, 'Government Fine')

TransferBetweenAccounts(fromKey, toKey, amount, reason) — move money between two shared accounts.

local ok, err = exports.BenzyMoney:TransferBetweenAccounts('lsac', 'government', 500, 'Tax')

Server exports — money requests

Create and manage money requests from any resource (e.g. a phone banking app). A request asks one party to pay another; the payer accepts or denies it in the /money menu or via RespondToRequest. See the matching request events in EVENTS.md.

RequestMoney(fromIdentifier, toIdentifier, amount, reason) → request id (or nil). from is who gets paid (the requester); to is who is asked to pay.

-- Ask player 5 to pay $250 to the player who triggered this
local requestId = exports.BenzyMoney:RequestMoney(source, 5, 250, 'Split the bill')

GetIncomingRequests(identifier) → array of pending requests asking this identifier to pay.

local inbox = exports.BenzyMoney:GetIncomingRequests(source)
for _, r in ipairs(inbox) do print(r.fromName, r.amountText, r.reason) end

RespondToRequest(src, requestId, accept) → boolean. Accept (true) or deny (false) a request on behalf of player src.

local ok = exports.BenzyMoney:RespondToRequest(source, requestId, true) -- accept

CancelRequest(src, requestId) — cancel a request that src created.

exports.BenzyMoney:CancelRequest(source, requestId)

Server exports — loans + bank account

The optional loan system (Config.Loans.Enabled). Loans pay out of, and are repaid into, the reserved bank account (the funding pool). All amounts are whole numbers; interest rates are basis points (500 = 5.00%). Loan events are in EVENTS.md. These return nil/{}/0 (reads) or false, 'LOANS_DISABLED' (actions) when loans are off.

The bank account is a normal shared account with the key 'bank', so the account exports above also work on it: GetAccountBalance('bank'), AddToAccount('bank', amount, reason), RemoveFromAccount('bank', amount, reason). benzy.admin can adjust it from the Staff tab.

GetBankBalance() → the bank pool's current balance.

print(exports.BenzyMoney:GetBankBalance())

GetLoan(loanId) → one loan's data (or nil).

local loan = exports.BenzyMoney:GetLoan(7)
if loan then print(loan.status, loan.outstanding, loan.rateBp) end

GetPlayerLoans(identifier) → array of a player's loans (active + historical). Offline ok.

for _, l in ipairs(exports.BenzyMoney:GetPlayerLoans(source)) do print(l.id, l.outstandingText) end

GetLoanDebt(identifier) → the player's total outstanding debt across live loans. Offline ok.

if exports.BenzyMoney:GetLoanDebt(source) > 0 then print('Still owes the bank.') end

GetAllLoans(filter) → every live loan. filter = 'all' | 'active' | 'pending' | 'offered' | 'delinquent'.

local behind = exports.BenzyMoney:GetAllLoans('delinquent')

IssueLoan(identifier, amount, opts)ok, loanId | errorCode. Issues a loan to a player (offline ok), funded from the bank pool. opts (optional) overrides { rateBp, interestMode, minPaymentMode, minPaymentValue, intervalSeconds }.

local ok, loanId = exports.BenzyMoney:IssueLoan(source, 10000, { rateBp = 300 })

RepayLoan(identifier, loanId, amount)ok, outstanding | errorCode. Pays from the borrower's bank toward the loan (offline ok).

local ok, left = exports.BenzyMoney:RepayLoan(source, loanId, 2500)

ForceCollectLoan(loanId, amount)ok, collected | errorCode. Pulls from the borrower's bank toward a delinquent loan (only allowed past Config.Loans.ForceCollectThreshold). amount of 0/nil collects as much of the balance as their bank allows.

local ok, took = exports.BenzyMoney:ForceCollectLoan(loanId, 0)

Server exports — notifications

Drop a message into a player's in-menu notifications center (the bell with the unread badge). Works for offline players too — it waits in their center until they next look. See BenzyMoney:NotificationPushed in EVENTS.md.

PushNotification(identifier, title, body, kind, data) → notification id (or false). kind (optional) sets the color accent ('info' default; money_* green, request_* gold, staff_* red, loan_* amber). data (optional) is any table stored alongside it.

exports.BenzyMoney:PushNotification(source, 'Paycheck', 'The city paid you $1,500.', 'money_received', { amount = 1500 })

Client exports

Read-only access to the calling player’s own balances (kept in sync by the server) — great for HUDs and phone apps.

GetMyCash() → number. The calling player’s own cash.

local cash = exports.BenzyMoney:GetMyCash()

GetMyBank() → number. The calling player’s own bank.

local bank = exports.BenzyMoney:GetMyBank()

GetMyMoney(){ cash, bank, total }. The calling player’s own balances.

local money = exports.BenzyMoney:GetMyMoney()
print(money.cash, money.bank, money.total)

GetMyAccountNumber() → string (or nil). The calling player’s own account number.

local number = exports.BenzyMoney:GetMyAccountNumber()

FormatMoney(amount) → string. The same formatter, client-side.

local text = exports.BenzyMoney:FormatMoney(1500) -- "$1,500"

Notify(kind, title, message, duration) — raise a notification through BenzyMoney. kind: 'success', 'error', 'info', or 'request'.

exports.BenzyMoney:Notify('success', 'Bank', 'Payment received', 4000)

Worked example: phone banking app

A phone resource that shows the player’s balance, lets them transfer money, and shows recent transactions.

Client (phone UI side):

-- Show the balance in the phone
local money = exports.BenzyMoney:GetMyMoney()
SendNUIMessage({ action = 'bank', cash = money.cash, bank = money.bank })

-- Keep it live: BenzyMoney pushes balance changes to the client
RegisterNetEvent('BenzyMoney:UpdateBalance', function(data)
SendNUIMessage({ action = 'bank', cash = data.cash, bank = data.bank })
end)

-- The player taps "send" in the phone
RegisterNUICallback('transfer', function(data, cb)
TriggerServerEvent('myphone:transfer', data.targetId, data.amount)
cb('ok')
end)

Server (phone backend):

RegisterNetEvent('myphone:transfer', function(targetId, amount)
local src = source
local ok, err = exports.BenzyMoney:Pay(src, tonumber(targetId), tonumber(amount), 'bank', 'bank', 'Phone transfer')
if not ok then
TriggerClientEvent('myphone:notify', src, 'Transfer failed: ' .. err)
end
end)

-- Recent transactions for the phone's history screen
RegisterNetEvent('myphone:getHistory', function()
local src = source
local tx = exports.BenzyMoney:GetTransactions(src, 20)
TriggerClientEvent('myphone:history', src, tx)
end)

Worked example: a fine system

-- A police resource issues a fine: money leaves the player and lands in the government account
RegisterNetEvent('police:fine', function(targetId, amount, reason)
local officer = source
if not exports.BenzyMoney:CanUseAccount(officer, 'government') then return end -- benzy.gov gate

local ok, err = exports.BenzyMoney:PayPlayerToAccount(targetId, 'government', amount, reason or 'Police fine')
if ok then
TriggerClientEvent('police:notify', officer, 'Fine issued.')
else
TriggerClientEvent('police:notify', officer, 'Could not fine: ' .. err)
end
end)