Money and banking
money.transfer between two accounts, the banking script through ai-core, and bills through whatever billing script runs.
import { money, banking, billing } from "@aicore-fivem/lib/server";A player's single account changes (add, remove, read a balance) are ai-core's exports (AddMoney, RemoveMoney, GetMoney; see ai-core server exports). The lib adds what needs more than one account change, and the banking and billing layers.
money
money.transfer
Moves money from one account to another in one database transaction, with a ledger row on both sides. Use it for anything where money must not appear or vanish half way: paying another player, a job paying a bonus, a fee.
Side: Server · Waits: no
money.transfer(from: MoneyRef, to: MoneyRef, amount: number, reason?: string, fee?: number): booleanNo Lua twin: call ai-core's export exports['ai-core']:TransferMoney(from, to, amount, reason, fee).
Parameters
Prop
Type
Returns
boolean: true when both rows were written. false when an amount is not a whole number, an account is missing, both are the same, or from cannot pay amount plus fee.
Example
import { onClientCallback, money, nearestPlayerTo, notify } from "@aicore-fivem/lib/server";
import { fail, oneArg, readInt } from "@aicore-fivem/lib/shared";
onClientCallback("my-cash:give", { args: oneArg((v) => readInt(v, 1, 100_000)), lock: true }, (source, amount) => {
const target = nearestPlayerTo(source, 2);
if (target === null) return fail("NOBODY_NEAR");
if (!money.transfer({ source, account: "cash" }, { source: target, account: "cash" }, amount, "give:cash"))
return fail("NOT_ENOUGH_CASH");
notify(target, `You received $${amount}`, "success");
return { ok: true };
});banking
banking talks to the banking script through ai-core's banking layer. Job money itself always moves through money or ai-core's exports.
banking.open
Opens the banking script's screen for a player.
Side: Server · Waits: no
banking.open(source: number): booleanlocal ok = aiLib.banking.open(source)Returns true when opened. false when the script cannot be opened from outside or none runs.
onClientCallback("my-atm:open", (source) => (banking.open(source) ? { ok: true } : fail("BANK_UNAVAILABLE")));banking.societyBalance
A job's society balance, for display. In ai-core's core account mode it is ai-core's job account; in own mode the banking script's own.
Side: Server · Waits: no
banking.societyBalance(job: string): number | nulllocal balance = aiLib.banking.societyBalance(job) -- number or nilReturns the balance, or null (Lua nil) when none runs or the script keeps none.
const balance = banking.societyBalance("mechanic") ?? 0;banking.provider
Side: Server · Waits: no
banking.provider(): string | nulllocal name = aiLib.banking.provider()Returns the banking script the layer uses, or null.
console.log(`banking through ${banking.provider() ?? "nothing"}`);billing
billing sends bills through whatever billing script runs; without one, ai-core's own bills (the player pays from a list on screen, the money moves when they pay). Texts are already translated.
billing.send
Sends a bill from a job (fines, service fees) or from a player.
Side: Server · Waits: no
billing.send(bill: BillRequest): booleanlocal ok = aiLib.billing.send(bill)BillRequest
Prop
Type
Returns
boolean: true when sent, false when invalid or refused.
Example
import { billing, nearestPlayerTo, online } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
function fine(officer: number, amount: number) {
if (!online.onDutyIn(officer, ["police"])) return fail("NOT_ON_DUTY");
const target = nearestPlayerTo(officer, 3);
if (target === null) return fail("NOBODY_NEAR");
return billing.send({ to: target, amount, label: "Speeding", from: officer, job: "police" })
? { ok: true }
: fail("BILL_FAILED");
}billing.unpaid
The player's open bills.
Side: Server · Waits: yes (Promise in TypeScript, yields the thread in Lua)
billing.unpaid(source: number): Promise<UnpaidBill[] | null>local bills = aiLib.billing.unpaid(source) -- table[] or nil, call inside a threadReturns UnpaidBill[] (id, label, amount still owed, sender), or null when the billing script cannot list them.
const bills = await billing.unpaid(source);
const owed = bills?.reduce((sum, bill) => sum + bill.amount, 0) ?? 0;billing.pay
The player pays one of their open bills.
Side: Server · Waits: no
billing.pay(source: number, id: string): booleanlocal ok = aiLib.billing.pay(source, id)Prop
Type
Returns true when paid. false when refused (not enough money, unknown bill) or the billing script takes payments only in its own screen.
if (!billing.pay(source, billId)) return fail("PAY_FAILED");billing.provider
Side: Server · Waits: no
billing.provider(): string | nulllocal name = aiLib.billing.provider()Returns the billing script bills go to, "ai-core" for ai-core's own bills.
if (billing.provider() === "ai-core") console.log("using ai-core's own bills");