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)