Skip to main content

Billing & Society

Invoice delivery channels and society/business account integrations

This section

Billing & Society

When a mechanic charges a customer (mod purchase, repair, custom invoice), money flows through two layers:

  1. Billing channel — how the bill reaches the player (tablet UI, ESX bill, qb-phone notification, instant deduction, etc.)
  2. Society deposit — where the paid money lands (mechanic's job/business account)

Both are auto-detected and configurable.

Billing Channels​

Set Config.Tablet.invoices.billing.script to one of the values below.

ScriptBehaviorBest for
internalBuilt-in tablet flow. Player sees the invoice on their mechanic tablet and accepts/pays from there.Self-contained setups, no external billing dependency
esx_billingTriggers esx_billing:sendBill. Pending bill appears in the player's ESX bill list.ESX Legacy with esx_billing
qs-billingCalls exports['qs-billing']:CreateBilling. Pending bill UI from Quasar.Quasar all-in-one stacks
okok_billingModern okokBilling:CreateCustomInvoice (8 params), with legacy okokBilling:Bill fallback for older installs.OKOK ecosystem
qb-bankingInstant deduction from the player's bank account + bank statement log. Falls back to internal pending bill if the player has insufficient bank funds.QBCore servers using qb-banking only (no phone billing)
Renewed-BankingInstant deduction + handleTransaction log. Same insufficient-funds fallback as qb-banking.Renewed-Banking users
qb-phoneInserts directly into qb-phone's phone_invoices table and refreshes the player's phone. The player accepts/declines via phone. qb-phone handles payment + society deposit on its end.QBCore servers using qb-phone for invoices
customTriggers your own event (customEvent) or export (customExport).Anything else (gksphone, lb-phone addon apps, etc.)

Society Deposit (Auto-Detect)​

When an invoice is paid, the money is automatically deposited into the mechanic's society / job account. The script scans for running banking resources and uses the first match in this priority order:

#ResourceExport called
1Renewed-BankingaddAccountMoney(jobName, amount)
2qb-bankingAddMoney(jobName, amount, reason)
3qs-bankingAddMoney(jobName, amount, reason)
4okokBankingAddMoney(jobName, amount)
5qb-managementAddMoney(jobName, amount)
6esx_addonaccountGetSharedAccount(society).addMoney(amount) (falls back to GetAccount for older forks)
7tgiann-bankAddJobMoney(jobName, amount)

If none of the above are running, the deposit step is skipped silently and a debug line is logged. The bill itself still goes through normally — money just doesn't end up in a society account.

Society Naming​

The society account name is always derived from the mechanic's job:

Mechanic's job (set in Mechanics Editor)Resulting society
mechanicsociety_mechanic
tuningsociety_tuning
lscustomssociety_lscustoms
bennyssociety_bennys

This means:

  • Two mechanic locations with the same job share one society (correct ESX/QB pattern — society = job).
  • Two mechanics with different jobs get separate society accounts (each job = its own kasa).

There is no global override. If you want Mechanic A and Mechanic B to use separate kasalar, give them different jobs in the Mechanics Editor.

Common Setups​

Recipes for typical server stacks. Set script and make sure the matching banking resource is running — the rest auto-wires.

QBCore + qb-phone (most common)​

lua
Config.Tablet.invoices.billing.script = 'qb-phone'

Player receives the invoice on their qb-phone, accepts/declines from the Bills app. qb-phone handles deposit into the mechanic job account.

QBCore + qb-banking only (no phone)​

lua
Config.Tablet.invoices.billing.script = 'qb-banking'

Money deducted instantly from the player's bank. If insufficient, falls back to internal tablet bill so the player can pay later. Society deposit goes into qb-banking job account.

Quasar all-in-one​

lua
Config.Tablet.invoices.billing.script = 'qs-billing'

qs-billing creates the pending bill, qs-banking auto-detected for society deposit.

ESX Legacy + esx_billing + esx_addonaccount​

lua
Config.Tablet.invoices.billing.script = 'esx_billing'

esx_billing:sendBill fires with the mechanic's society_<job>. esx_billing deposits to the matching addon account.

Renewed-Banking (any framework)​

lua
Config.Tablet.invoices.billing.script = 'Renewed-Banking'

Instant bank deduction + transaction log + society deposit to the job account.

Internal only (no external dependency)​

lua
Config.Tablet.invoices.billing.script = 'internal'

The mechanic tablet handles everything. Society deposit still attempts auto-detect — if a banking script is running, the money lands there; otherwise the deposit step is skipped (the bill still completes).

Migration from Older Versions​

If you're updating from a version that used the old billing.esxSociety global override:

  • The esxSociety and society config fields are now deprecated no-ops. They are silently ignored.
  • The script now derives the society per-mechanic from each mechanic's job.
  • If all your mechanics use the same job (e.g. 'mechanic') and your society is named society_mechanic, no action needed — behavior is identical.
  • If you have mechanics with different jobs (e.g. mechanic, tuning), each one now correctly deposits to its own society. Make sure those society accounts (society_tuning, etc.) exist in your banking system.

Troubleshooting​

"Player paid but the money never showed up in the business account"​

  1. Check server console for [CODE9_MECHANIC] [INVOICE] No banking script detected — means none of the supported banking resources are running.
  2. Check for [INVOICE] <script> society deposit error: ... — your banking script's export errored, usually because the society_<job> account doesn't exist. Create it in your banking system.
  3. Confirm your mechanic's job field in the editor matches the actual job name registered in your framework.

"qb-phone bill never appears"​

  1. Confirm qb-phone resource is running and the phone_invoices table exists.
  2. Confirm the target player has a registered qb-phone (PlayerData populated).
  3. Check for [INVOICE] qb-phone error: ... lines in the console.

"okok_billing invoice has no author / wrong sender"​

Resolved in the latest version — invoiceSource parameter is now passed as the server source ID (number) per okok's documented signature. Older builds passed the sender's display name (string), which some okok versions rejected.

"esx_addonaccount returns nil for my society"​

The script now calls GetSharedAccount(name) first (the canonical ESX Legacy method) and falls back to GetAccount(name) for older forks. If both return nil, the society account simply doesn't exist — create it with:

sql
INSERT INTO addon_account (name, label, shared) VALUES ('society_yourjob', 'Your Job', 1);
INSERT INTO addon_account_data (account_name, money) VALUES ('society_yourjob', 0);