
BenzyMoney
A complete, standalone money/economy system for FiveM — no framework (ESX/QBCore) required. Every player has a cash and bank balance, there is a shared government/society account and any number of business accounts, an in‑game /money menu for sending and requesting money, working ATMs, a staff tool for adjusting balances, Discord webhooks, and a full exports/events API so any other resource (jobs, shops, fines, phone banking apps, …) can plug in.
BenzyMoney runs on BenzyBridge for its on‑screen prompts, storage, and permissions. The bridge auto‑detects your stack, so the same install works standalone or alongside ESX / QBCore / QBox — and because BenzyMoney is the money engine, money works fully even with no framework at all.
Made by Samuel Benzy of Benzy Development
Features
- Cash + bank balances per player, saved per Rockstar license.
- Database or file storage — handled by BenzyBridge (MySQL via oxmysql/mysql-async, or a pure JSON file mode). BenzyMoney runs its own tables through whichever the bridge picks.
- Auto‑creates its database tables on first start (or run the included
install.sqlyourself). - Government/society account that fines and government‑service payments flow into, and that government members can spend from.
- Business accounts — a configurable list; add/rename/remove businesses by editing the config and restarting.
- /money menu (in‑game UI) with Personal, Government, per‑Business, and Staff tabs, each shown only to players with permission.
- Send & Request money with fuzzy search for players, businesses, or the government — including offline players. Requests made to offline players are delivered when they next log in.
- Account numbers — every player gets a unique account number, shown on the ATM screen and their Personal tab; people can send/request by account number instead of by name.
- Optional reason on every send/request, shown in the recipient’s inbox and the Discord logs (it even says when no reason was given).
- ATMs — walk up to any in‑game ATM and press a key for a dedicated ATM screen to deposit/withdraw. Optionally force deposits/withdrawals to only happen at an ATM.
- Periodic payout — optionally pay every online player a set amount at a set interval (e.g. a government assistance deposit every 30 minutes of continuous play).
- “Received while away” notice — players are told how much arrived while they were offline the next time they log in.
- Staff controls —
benzy.staffcan adjust player balances;benzy.admincan also adjust government, business, and bank accounts. - Loans (optional) — a full lending system: borrow from a central bank account, automatic interest + payment cycles, a
benzy.loanmanager role, multiple loans, refinancing, delinquency tracking, and force‑collection. Auto (instant) or manual (approval) mode. - Notifications center — an in‑menu alerts panel with an unread badge for money received, requests accepted/denied, loan events, and staff adjustments — with a scrollable, dismissable history and a
PushNotificationexport. - Discord webhooks — separate channels for personal, business, government, staff, loan, and bank activity.
- Localization — every string lives in
locales/. - Big exports/events API — read and move money from any other resource, with live balance‑change events.
Requirements
- A FiveM server (artifact build with
fx_version 'cerulean'). - BenzyBridge, started before BenzyMoney — it provides BenzyMoney's on-screen prompts, storage connection, and unified access checks. Choose the storage mode in BenzyBridge's config. BenzyMoney depends on BenzyBridge, so it must load after the bridge.
- Optional — a framework. BenzyMoney is standalone, but if you run ESX, QBCore, or QBox, start it before BenzyBridge so the bridge detects it. BenzyMoney stays the money engine either way; the framework only feeds the
Frameworkaccess method (below) and job/gang lookups. - Database mode only: a MySQL connector (oxmysql or mysql-async) started before BenzyBridge. File mode needs nothing.
Load order (
server.cfg). SQL connector → framework (if any) → BenzyBridge → prompt providers → BenzyMoney. The bridge must be up before BenzyMoney, and any prompt provider it routes to before that.
Installation
- Drop the
BenzyMoneyfolder into your server’sresourcesdirectory. - Storage is decided by BenzyBridge (its
Config.Storage): a database if a connector is running, otherwise JSON files. BenzyMoney runs its own tables through whichever the bridge picks. - Add to your
server.cfg:ensure oxmysql # SQL connector — database mode only (or your mysql-async resource)ensure es_extended # your framework, if any (ESX / QBCore / QBox) — optional; skip it to stay standaloneensure BenzyBridge # detects your stack; provides prompts, storage, and accessensure BenzyMoney # loads after the bridge and its providers - Set up permissions (see Permissions below) and Discord webhooks (optional).
- Start the server. When a database is used,
Config.AutoInsertSQL = true(the default) checks the schema on every start and creates or repairs anything missing — or runinstall.sqlby hand and set it tofalse. BenzyMoney prints which storage it chose, and the result of the schema check, on boot.
That’s it. Players are added to storage automatically when they first join, with the starting cash/bank from the config.
What works with — and without — a framework
BenzyMoney is the money system, so it does not need a framework, an inventory, or any other money resource. Everything it does works on a bare, standalone server; a framework only unlocks a couple of extra convenience paths.
| Concern | Standalone (no framework) | With a framework / provider |
|---|---|---|
| Money — cash, bank, accounts, businesses, fines, requests, loans | Fully works. BenzyMoney is the money engine, so every balance, transfer, and export runs regardless of framework. It is also the suite's money provider, so Benzy.* money calls from other Benzy resources route here. | Same — BenzyMoney stays the engine. A framework's own cash/bank is not used. |
| Storage | Bridge file mode — JSON files in the resource's data/ folder. No database needed. | Bridge database mode — MySQL via oxmysql / mysql-async. Set the mode in BenzyBridge. |
| Access / permissions | ACE, raw identifiers, or Discord roles carry the check (the Framework method is skipped). | Add a framework job or group to any role's Framework method as well. |
| Inventory | Not used at all — BenzyMoney tracks money in its own tables/files, so there is nothing to fall back from and no warning is ever printed. | Not used either; money is never an inventory item. |
The only thing a framework adds is the Framework access method (gate a tab by a job/group) and job/gang lookups the bridge exposes elsewhere — money itself is unaffected.
Configuration
Everything is configured in config.lua, and every option has a comment above it explaining what it does. The highlights:
Storage
BenzyBridge decides whether balances are saved to a database or to JSON files (and which SQL connector to use). BenzyMoney keeps its own tables + data settings:
| Option | What it does |
|---|---|
Config.AutoInsertSQL | Verify the tables/columns/keys on every start and create or repair anything missing (printing what it checks and fixes); it also warns about wrong column types without altering them (to protect your data). When false, it only verifies and warns. Ignored in file mode. |
Money & limits
| Option | What it does |
|---|---|
Config.StartingCash / Config.StartingBank | What brand‑new players begin with. |
Config.CurrencySymbol / Config.CurrencyPosition | How amounts are shown, e.g. $1,000 or 1,000$. |
Config.MaxBalance | Hard cap per cash/bank balance (overflow guard). |
Config.MaxTransaction | Most money that can move in a single operation. |
Config.RateLimit | Minimum milliseconds between player‑driven actions (anti‑spam). |
Players & history
| Option | What it does |
|---|---|
Config.LogTransactionsToDatabase | Write a full transaction history to the database (database mode). |
Config.HistoryLimit | How many recent transactions the menu/history shows. |
Account numbers & periodic payout
| Option | What it does |
|---|---|
Config.AccountNumber | Length + optional Prefix for the unique account number every player gets. |
Config.Payout | Pay every online player Amount into their bank every IntervalMinutes of consecutive online time (a relog resets the timer). Has Enabled and a configurable Message. |
Sending, requesting, reasons
| Option | What it does |
|---|---|
Config.SendAccounts | Whether players may send from cash, bank, or both. |
Config.CashProximity | When Enabled, players must be within MaxDistance meters to hand over cash in the menu (otherwise they must use a bank transfer). Bank transfers are never distance‑limited. |
Config.RequestExpiry | Seconds a money request stays valid (default 7 days; 0 = never). Gives offline requests time to be delivered. |
Config.PersistRequests | Save pending requests so they survive a restart. |
Config.RequireReason | Force a reason on sends/requests. |
Config.MaxReasonLength / Config.NoReasonText | Reason length cap and the “no reason” fallback text. |
Government & businesses
| Option | What it does |
|---|---|
Config.GovernmentLabel / Config.GovernmentStartingBank | The society account’s name and first‑run balance. |
Config.Businesses | The list of businesses (see Businesses below). |
Config.DefaultBusinessStartingBank | Default first‑run balance for a new business. |
Config.OnBusinessRemoved | What to do when a business leaves the list: keep (default), archive, transfer, or delete. |
Loans & bank account (optional)
Off by default. Loans pay out of, and are repaid into, a reserved bank account (the lending pool). See Loans below.
| Setting | What it does |
|---|---|
Config.Loans.Enabled | Master switch for the whole loan system (and the bank account). |
Config.Loans.Mode | 'auto' (borrow instantly) or 'manual' (request → a benzy.loan manager sets the rate → you accept/decline). |
Config.Loans.InterestMode / InterestRateBp | 'compound' (on the balance) or 'simple' (on the principal); rate per cycle in basis points (500 = 5%). |
Config.Loans.PaymentIntervalSeconds | How often interest is charged and a payment is due. |
Config.Loans.MinPaymentMode / MinPaymentPercentBp | The minimum each cycle: 'interest' (at least the interest) or 'percent' (a % of the balance). |
Config.Loans.MaxLoanPerLoan / MaxTotalDebt / MaxActiveLoans | Per‑loan cap, combined‑debt cap (0 = none), and simultaneous‑loan cap (0 = unlimited). |
Config.Loans.ForceCollectThreshold / ResetDelinquencyOnGoodCycle | Missed payments before a manager may force‑collect, and whether catching up clears that count. |
Config.Loans.SchedulerIntervalSeconds / MaxCatchupCycles / CatchupChargesDelinquency | The payment‑cycle sweeper: how often it runs, the catch‑up cap after downtime, and whether downtime counts as delinquency. |
Config.Loans.AllowSelfApprove / RequestExpirySeconds / OfferExpirySeconds | Manual mode: may a manager approve their own request, and how long pending requests/offers last. |
Config.Bank.Label / Config.Bank.StartingBank | The bank account's display name and first‑run balance (the lending pool). |
Basis points (the …Bp settings). Both InterestRateBp and MinPaymentPercentBp are written in basis points. A basis point is one hundredth of a percent, so 100 = 1%, 250 = 2.5%, 500 = 5%, and 1000 = 10% (to convert a percent to basis points, multiply by 100 — e.g. 7.5% → 750). They're used so you can set fractional rates without decimals.
Deposit/withdraw & ATMs
See ATMs & deposit/withdraw below. Config.Interaction ('drawtext' or 'target') sets how a world ATM is opened; the rest lives under Config.DepositWithdraw.
Access
Who may use each privileged tab. Lives under Config.Access (plus a per‑business Access on each Config.Businesses entry). See Permissions below for the four‑method model.
Notifications & locale
| Option | What it does |
|---|---|
Config.NotifyOfflineReceived | Tell players how much money arrived while they were offline, on their next login. |
Config.Locale | Fallback language code (default 'en'). The active language is chosen by BenzyBridge and shared across the suite; this is only used until the bridge resolves one. |
Webhooks
Config.Webhooks holds one URL per channel (Personal, Business, Government, Staff, Loans, Bank, Errors). Leave a field empty to disable that log.
Commands
| Command | Who | What it does |
|---|---|---|
/money | Everyone | Opens the money menu. |
/balance | Everyone | Shows your cash + bank in a notification. |
/pay [id] [amount] [reason] | Everyone | Hands cash to a player. With no id, pays the closest player. |
These are the only player commands. Staff/admin balance changes are done in the /money menu’s Staff tab, and deposits/withdrawals happen at an ATM (and, if you allow it, the menu’s Bank tab) — none of those have a command.
Debug: debugbenzymoney (in the server console, or a player’s F8 console when Config.Debug = true) prints what BenzyBridge resolved for BenzyMoney and the storage state; in the F8 console it also lists which of your ace permissions you hold.
Permissions
Every privileged part of BenzyMoney is gated by a role in Config.Access, checked server‑side through BenzyBridge's unified Benzy.HasAccess. Each role is a rule with four methods that are OR'd together — any one that matches grants access, and a method whose prerequisite is absent (no framework, no Badger Discord API) is simply skipped:
| Method | Matches on | Notes |
|---|---|---|
Framework | A framework job or group name in list. | Only your active framework's list is read; standalone servers skip it. e.g. ESX 'admin'/'superadmin', QBCore/QBox 'god'/'admin'. |
Identifiers | Any of the player's raw identifiers in list. | license: / fivem: / steam: / discord: … |
AcePerms | A bare true/false toggle for the role's fixed ACE string. | When true, that role's ace (below) checked against the player’s ACE permissions. This is the only method on by default, so BenzyMoney behaves like a plain ace setup until you switch another on. |
Discord | The player's Discord role ids in list. | Needs Badger_Discord_API running; skipped if it isn't. |
Each method except AcePerms has an ENABLE flag and a list; flip ENABLE = true and fill the list to use it. The shape (from config.lua):
Config.Access = {
gov = {
Framework = { ENABLE = false, list = { 'admin', 'superadmin' } },
Identifiers = { ENABLE = false, list = { 'license:xxxxxxxxxxxxxxxx', 'fivem:1234567' } },
AcePerms = true, -- checks 'benzy.gov'
Discord = { ENABLE = false, list = { '123456789012345678' } },
},
-- staff, admin, loan, loanobserver follow the same shape
}
The roles
Role (Config.Access.<role>) | Fixed ACE string | Grants |
|---|---|---|
gov | benzy.gov | The Government tab — spend society funds. |
staff | benzy.staff | The Staff tab — add/remove player funds. |
admin | benzy.admin | Lets staff also adjust government + business + bank accounts (in the Staff tab). |
loan | benzy.loan | The Loan Manager view — approve/deny/edit/force‑collect everyone's loans, and view the bank account. |
loanobserver | benzy.loanobserver | (optional) View the bank account's balance + history (read‑only), without managing loans. |
| (per business) | benzy.business.<key> | That business's tab. Each entry in Config.Businesses carries its own Access rule with the same four‑method shape (keyed by its benzy.business.<key> ace). |
benzy.loan already includes viewing the bank account, so you only need benzy.loanobserver for someone who should see the lending pool without managing loans. Granting a player both is harmless but redundant.
Setting up the default ACE method (server.cfg)
AcePerms is on by default, so out of the box you grant access with aces:
# A staff/admin group
add_ace group.admin benzy.staff allow
add_ace group.admin benzy.admin allow
add_ace group.admin benzy.loan allow
# Government members
add_ace group.gov benzy.gov allow
# A business (key must match Config.Businesses)
add_ace group.mechanic benzy.business.lsac allow
# Put a person in a group by their license
add_principal identifier.license:abc123... group.admin
add_principal identifier.license:def456... group.gov
Prefer to gate a role by a framework job, raw identifier, or Discord role instead? Turn on that method in the role's rule in config.lua — you can mix them, and they all OR with the ace.
The menu only shows a tab if the player passes the role's rule, and the server re‑checks it on every action — a tampered client cannot reach an account it was not granted.
Businesses
Businesses live in Config.Businesses:
Config.Businesses = {
{ key = 'lsac', label = 'LS Auto Care', startingBank = 0 },
{ key = 'beanmach', label = 'Bean Machine' },
}
key— a stable id (lowercase letters/numbers/underscores). It is used in the acebenzy.business.<key>and in the exports. Don’t reuse a key for a different business.label— the display name. Rename freely.startingBank— optional first‑run balance.
On every start BenzyMoney syncs the list: it adds new businesses, updates changed labels, and handles removed ones according to Config.OnBusinessRemoved:
keep(default, safest) — keeps the account and its funds, just makes it unusable until you add the key back. Nothing is ever lost to a typo.archive— marks it archived; funds preserved.transfer— moves its balance into the government account, then deletes it.delete— permanently deletes the business and its funds (loudly warned in console + the staff webhook).
ATMs & deposit/withdraw
Moving money between cash and bank happens through a dedicated ATM screen (and optionally the menu’s Bank tab).
How a world ATM is opened is set by Config.Interaction:
| Value | What it does |
|---|---|
'drawtext' (default) | An on‑screen “[E] Use the ATM” key prompt shows near an ATM (rendered by BenzyBridge). Works everywhere, no dependencies. |
'target' | Uses a targeting system (ox_target / qb-target) — the one BenzyBridge detects. If no targeting system is running, BenzyMoney warns once and falls back to draw‑text, so this is always safe to set. |
Both paths open the same ATM screen. The rest of the deposit/withdraw behavior is under Config.DepositWithdraw:
| Option | What it does |
|---|---|
Enabled | Master on/off switch. |
RequireATM | true = deposits/withdrawals can only happen at a real ATM (no Bank tab in the menu). false = the menu also gets a Bank tab so it works anywhere; ATMs still work too. |
OpenKey | Key to open the ATM when stood at one (default E). Players can rebind it in FiveM’s keybinding settings. |
ShowHelpText | Show the “[E] Use the ATM” key prompt (rendered by BenzyBridge). |
ATMRadius | How close counts as “at” an ATM. |
ExtraATMModels | Extra world props to also treat as ATMs, on top of the built‑in GTA V ATMs. |
ExtraATMCoords | Optional fixed coordinates also treated as ATMs (for custom interiors with no ATM prop). |
Whatever you choose, the rest of the /money menu (send, request, government, business, staff) always works.
Money requests
In the Request tab a player asks someone to pay them. The target can be a player, a business, or the government (anyone who can act on that account sees the request in their Requests inbox and can Accept or Deny).
- If the target is offline, the request is saved and delivered the next time they join.
- Requests expire after
Config.RequestExpiry(default 7 days;0= never). - The optional reason is shown in the inbox and the Discord log.
- Funds are checked when the request is accepted, not when it is created.
Account numbers
Every player is given a unique account number the first time they join (set its length and an optional prefix with Config.AccountNumber). It is shown on the ATM screen and on their Personal tab in /money.
Anywhere you pick a recipient (Send or Request), you can type an account number instead of a name — handy when players would rather not be searched for by name. Numbers are guaranteed unique, so no two players share one. Other resources can read a player’s number with the GetAccountNumber export (or the client GetMyAccountNumber), and pass { accountNumber = '…' } as an identifier to any export.
Periodic payout
Turn on Config.Payout to pay every online player a set amount into their bank at a set interval — for example a government assistance direct deposit of $100 every 30 minutes.
The interval is consecutive online time: a player must stay connected for the full IntervalMinutes to be paid, and is then paid again every interval for as long as they stay online. Disconnecting resets the timer (15 minutes, a relog, then another 15 minutes does not count as 30). The notification text is set with Config.Payout.Message.
Loans
Turn on Config.Loans.Enabled to add a full lending system. Loans are funded from a reserved bank account (the lending pool) — set its starting balance with Config.Bank.StartingBank, top it up from the Staff tab (benzy.admin) or via the account exports. Players use the Loans tab in /money.
Two modes (Config.Loans.Mode):
auto— players borrow instantly, up to the caps, at the configured rate.manual— a player requests a loan; abenzy.loanmanager sets the interest rate and terms and sends an offer; the player accepts or declines. Both sides are notified at each step.
Interest + payments. Every PaymentIntervalSeconds, interest is added to the balance (InterestMode = compound on the balance, or simple on the original principal; the rate is in basis points). Each cycle the borrower must pay at least the minimum (MinPaymentMode = interest, or a percent of the balance) or they go delinquent. The scheduler catches up cycles missed during a restart without punishing players for server downtime.
Managing loans. A benzy.loan manager gets a Loan Manager view over everyone's loans (who owes, who's behind) and can approve/deny requests, edit/refinance a loan (change the rate, lend more, or write part of it down), and force‑collect from a delinquent borrower's bank once they've missed ForceCollectThreshold payments. Managers can take loans themselves.
Limits. MaxLoanPerLoan caps a single loan, MaxTotalDebt caps a player's combined debt, and MaxActiveLoans caps how many they hold at once. Players can hold several loans, pay any amount, pay one off in full, or (in auto mode) borrow more on an existing loan.
History. Money moving to/from a loan shows in the borrower's normal Personal history; the full per‑loan log (issued, interest, payments, edits, delinquency, force‑collects, payoff) lives in the Loans tab. Loan activity is also logged to the Loans Discord webhook. Other resources can read and drive loans through the loan exports and events.
Notifications center
The /money menu has a second bell — the notifications center — with an unread badge. Players get an alert when they receive money, when a request they sent is accepted or denied, for every loan event, and when staff adjust their balance. Notifications are persisted per player (so they survive a relog and even arrive while offline), and can be scrolled, marked read, deleted one‑by‑one, or cleared. The in‑menu notifications center is always on, with no configuration.
Any resource can drop a notification into a player's center with the PushNotification export.
Storage modes
BenzyMoney stores its data wherever BenzyBridge is set to (its Config.Storage) — BenzyMoney just runs its own tables/files through the bridge:
- Database: balances live in MySQL (via oxmysql or mysql-async). Its tables are created/repaired on boot when
Config.AutoInsertSQL = true, or run the includedinstall.sqlyourself. - File: balances are saved as JSON and persisted automatically (see
Config.AutosaveIntervalSeconds), so nothing is lost across restarts.
Set the mode (and connector) in BenzyBridge. Balances do not automatically migrate between a database and JSON files.
Discord webhooks
Paste your webhook URLs into Config.Webhooks. Each kind of activity goes to its own channel so nothing gets mixed up:
| Channel | Logs |
|---|---|
Personal | Player cash/bank changes and transfers. |
Business | Business deposits, withdrawals, payroll. |
Government | Fines in, government spending, salaries. |
Staff | Staff/admin overrides — money created or destroyed (your audit channel). |
Loans | Loan activity — issued, repaid, delinquency, force‑collects. |
Bank | Bank account (lending pool) balance changes. |
Errors | Optional: storage errors / failed privileged operations. |
Every money embed includes a Reason line, showing the reason that was given or Config.NoReasonText (“No reason provided.”) when none was. Leave a URL empty to disable that channel.
Localization
All text is in locales/. To translate:
- Copy
locales/template.luatolocales/<code>.lua(e.g.locales/de.lua). - Change the
Locales['xx']line to your code and translate the right‑hand strings (keep the%s/%dplaceholders). - Restart — every file in
locales/loads automatically. The active language comes from BenzyBridge (shared across the suite);Config.Localeis only the fallback used until the bridge resolves one.
Anything you don’t translate falls back to English automatically.
Integrating with other resources
BenzyMoney exposes a large exports/events API — read balances, move money, run payroll/fines, and react to live balance changes. See:
- docs/EXPORTS.md — every export with copy‑paste examples (including a worked phone‑banking and a fine‑system example).
- docs/EVENTS.md — every event you can listen to or trigger.
- docs/INTEGRATIONS.md — copy‑paste setup guides for specific resources (e.g. JG HUD), with exact paste locations.
Quick taste:
-- Server: give a player $500 cash
exports.BenzyMoney:AddCash(source, 500, 'Daily reward')
-- Server: take a $250 fine from a player's bank and send it to the government account
exports.BenzyMoney:PayPlayerToAccount(source, 'government', 250, 'Speeding fine')
-- Client: read your own balance for a HUD
local money = exports.BenzyMoney:GetMyMoney() -- { cash, bank, total }
Notes
- Money is handled as whole numbers (no cents).
- All money logic is server‑authoritative. Clients never set balances; they only ask, and the server validates every amount and permission.
- Sending to a player uses cash or bank (the sender chooses, where valid). Businesses and government are bank‑only.
- Players are identified by their Rockstar license; anyone without one isn’t added to the money script. Each player also has a stable numeric database id (included in BenzyMoney’s events/exports) so a license can be re‑pointed by hand without breaking their money.
Troubleshooting
- Money is disabled on boot — BenzyBridge isn’t started, or its storage failed (e.g. a database is forced in BenzyBridge but no connector is running).
ensure BenzyBridge(and your connector) before BenzyMoney; checkdebugbenzymoneyor BenzyBridge’s boot summary. - Tables not created — make sure
Config.AutoInsertSQL = true(database mode), or runinstall.sqlby hand. - A tab is missing in /money — that player doesn’t pass that role's
Config.Accessrule (by default, the matching ace:benzy.gov,benzy.business.<key>,benzy.staff,benzy.admin). Re‑check yourserver.cfg(or the role's other methods if you enabled them).debugbenzymoneyin a player's F8 console lists which roles they hold. - Deposits/withdrawals only work at an ATM — that’s
Config.DepositWithdraw.RequireATM = true. Set it tofalseto allow the menu’s Bank tab anywhere. - Webhook not posting — the URL is empty or wrong. Turn on
Config.Debugto see delivery logs in the server console. - Nothing happens / errors on boot — turn on
Config.Debugand read the server console; it logs storage init, account sync, and player loads.
Support
Need help? Visit support.benzy.lol.
Credits
Made by Samuel Benzy of Benzy Development.
Website: https://benzy.lol