AI Core

Money and banking

money.transfer between two accounts, the banking script through ai-core, and bills through whatever billing script runs.

TypeScript
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

Signature
money.transfer(from: MoneyRef, to: MoneyRef, amount: number, reason?: string, fee?: number): boolean

No 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

Signature
banking.open(source: number): boolean
Lua
local 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

Signature
banking.societyBalance(job: string): number | null
Lua
local balance = aiLib.banking.societyBalance(job) -- number or nil

Returns 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

Signature
banking.provider(): string | null
Lua
local 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

Signature
billing.send(bill: BillRequest): boolean
Lua
local 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)

Signature
billing.unpaid(source: number): Promise<UnpaidBill[] | null>
Lua
local bills = aiLib.billing.unpaid(source) -- table[] or nil, call inside a thread

Returns 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

Signature
billing.pay(source: number, id: string): boolean
Lua
local 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

Signature
billing.provider(): string | null
Lua
local 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");

On this page