legacy-billing
Integration
Exports and events for integrating other resources with legacy-billing.
Integration
Open the billing panel (client export)
Opens the NUI billing panel for the local player. Fetches init data via legacy-billing:getInitData and shows the panel; no-ops if already open or if init data fails to load.
Put this in: any client-side Lua file of your resource.
exports['legacy-billing']:OpenBilling()
Create a bill programmatically (server export)
CreateBill(src, targetId, amount, description, jobName, dueDate, metadata)
src— the source of the player issuing the bill; pass0(ornil) for a system-generated bill (recorded as sent by"system").targetId— identifier of the player being billed.amount— number, must be> 0.description— string, validated/sanitized (Config.MaxDescriptionLengthapplies).jobName— should match a row inlegacy_billing_jobsfor a proper label; if no matching row exists, the label falls back tojobNameitself. This export does not checkcan_bill— it bypasses the normal job-biller permission check entirely, so any resource calling it can invoice on behalf of any job name.dueDate— optional, string timestamp (e.g.'2025-06-15 23:59:59').metadata— optional table, stored as JSON.
Returns the new bill's ID on success, or nil if validation fails (missing target/amount/description/jobName, amount <= 0, or description fails sanitization).
Put this in: any server-side Lua file of your resource.
-- Police issuing a traffic fine
local billId = exports['legacy-billing']:CreateBill(
source,
targetIdentifier,
5000,
'Traffic Fine - Speeding in a school zone',
'police'
)
-- Hospital bill with due date and metadata
local billId = exports['legacy-billing']:CreateBill(
source,
targetIdentifier,
15000,
'Emergency room treatment and medication',
'ambulance',
'2025-06-15 23:59:59',
{ treatmentId = 'ER-4821', doctor = 'Dr. Smith' }
)
-- System-generated bill (no player source)
local billId = exports['legacy-billing']:CreateBill(
0,
playerIdentifier,
2500,
'Monthly property tax',
'government'
)
Listening for billing activity (server-local events)
These are fired locally on the server with TriggerEvent (not networked) whenever billing state changes. Any server-side resource can hook them with AddEventHandler.
Put this in: any server-side Lua file of your resource.
-- Fired after a bill is created (via createBill callback or the CreateBill export)
AddEventHandler('legacy-billing:billCreated', function(data)
-- data.billId, data.senderId, data.targetId, data.amount, data.jobName
end)
-- Fired after a successful full or partial payment
AddEventHandler('legacy-billing:billPaid', function(data)
-- data.billId, data.payerId, data.amount, data.method ('cash'|'bank')
end)
-- Fired after an admin cancels a bill
AddEventHandler('legacy-billing:billCancelled', function(data)
-- data.billId, data.cancelledBy
end)
Direct database access
Since billing data lives in plain MySQL tables, you can also query it directly with oxmysql from your own resource if you need read access outside of the exported API:
-- Get unpaid/partial/overdue bills for a player
local bills = MySQL.query.await(
'SELECT * FROM legacy_bills WHERE target_id = ? AND status IN (?, ?, ?)',
{ identifier, 'unpaid', 'partial', 'overdue' }
)
-- Get total outstanding amount
local total = MySQL.scalar.await(
'SELECT COALESCE(SUM(amount - amount_paid), 0) FROM legacy_bills WHERE target_id = ? AND status IN (?, ?, ?)',
{ identifier, 'unpaid', 'partial', 'overdue' }
)
amount,amount_paid, andlate_fee_amountare stored asINT(whole-dollar units, no decimal/cents precision) — keep any external integration consistent with that.