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);