Developers
The lation shops server and client exports, the server events it fires, its hooks and custom stock deliveries, with parameters, return shapes and Lua examples.
A shop is addressed by its shop ID, the one set on its Setup page. A player is a server id or an identifier: the citizenid on Qbox and QBCore, the player identifier on ESX.
The read exports never change anything: every write that moves money or stock stays inside lation shops, behind its locks and checks. The two delivery exports are the one way in, for finishing a stock order. Returned tables are copies, so changing them has no effect on the shop.
Server exports
| Export | Returns |
|---|---|
openShop(source, shopId) | boolean. Opens a shop for a player. |
GetShop(shopId) | A shop, or nil |
GetAllShops() | Every shop, by shop ID |
GetShopBalance(shopId) | number, or nil |
GetShopOwner(shopId) | The owner, or nil |
GetOwnedShops(identifier) | The shops a player owns |
IsShopEmployee(shopId, identifier) | boolean |
GetShopEmployees(shopId) | The staff |
GetShopStats(shopId) | The dashboard's figures, or nil |
GetShopBankAccount(shopId) | The account id at lation banking, or nil |
GetConfig(sectionId?) | A copy of the live configuration |
CompleteStockOrder(orderId) | boolean |
CancelStockOrder(orderId) | boolean |
openShop
Server export
local opened = exports.lation_shops:openShop(source, shopId)Parameters
sourcenumber- The player's server id
shopIdstring- The shop to open
Returns
booleantruewhen the screen opened,falsewhen there is no such shop or player, or a check refused
Opens the screen that matches the shop's mode, as the client export does: the buy screen, the sell screen, or both as two tabs. It skips the distance check for that session, so every purchase and sale made before the player closes it skips it too. The hours, the job requirement, the OnBeforeShopOpen hook and the item requirement are still checked, and a refusal reaches the player as a notification. A player who opens shops more than 10 times in 10 seconds is refused without one.
A Sell Only shop is never bought from, whatever opened it: the server refuses every purchase there.
-- after your own code has decided the player may use the shop
if not exports.lation_shops:openShop(source, '24_7_store') then
print(('%s could not open the 24/7 Store'):format(GetPlayerName(source)))
endOnly call it from code that has already decided the player may use the shop: the session it opens buys and sells from anywhere.
GetShop
Server export
local shop = exports.lation_shops:GetShop(shopId)Parameters
shopIdstring- The shop ID
Returns
table | nil- The shop, read fresh from the database (below), or
nilwhen there is no such shop
The shop, with the fields you are most likely to read:
{
id = '24_7_store',
title = '24/7 Store', -- the name players see
subtitle = 'Your neighborhood convenience store',
currency = '$',
currencySuffix = false, -- true shows 100$ instead of $100
shopMode = 'buy', -- 'buy', 'sell' or 'both'
balance = 18450,
ownerIdentifier = 'ABC12345', -- nil while the server runs it
ownerName = 'John Doe',
forSale = false,
salePrice = 125000,
purchaseAmount = 125000, -- what this owner paid; 0 when it was given
catalogIds = { 'general' }, -- in merge order
catalogStocking = false, -- Stock from catalogs
locations = {}, -- { type = 'coords' | 'ped' | 'model', coords, model?, scenario?, models?, label?, showBlip?, delivery? }
blip = nil, -- { label, sprite, color, scale }, or nil
categories = {}, -- { id, label, icon?, iconColor? }
paymentMethods = {}, -- { id, label, icon?, type = 'player' | 'society' | 'custom', minGrade? }
revenueShares = {}, -- { id, job, jobLabel, percentage }
jobRestriction = nil, -- { jobs = { { job, minGrade } } }, or nil
operatingHours = nil, -- { enabled, openTime, closeTime }, or nil
itemRequirement = nil, -- { item, removeOnOpen } for one item, { items = { { item, removeOnOpen } }, requireAll } for several, or nil
randomPrices = nil, -- { enabled, percentage, interval }, or nil
sellPricePercentage = nil, -- the shop's Default Sell Price (%)
sellPaymentSource = nil, -- { type = 'server' | 'society' | 'shop_balance', account?, delivery = 'cash' | 'bank' | 'custom', deliveryItem? }
activeSale = nil, -- the running sale (below), or nil
allowStockDeposit = true,
allowStockWithdraw = false,
managementLocation = nil, -- { x, y, z }, or nil
deliveryLocation = nil, -- { x, y, z, w }, or nil
inventory = {}, -- the listings (below)
}A listing:
{
listingId = 42,
item = 'water_bottle',
label = 'Water Bottle',
description = nil,
category = 'drinks',
icon = 'nui://ox_inventory/web/images/water_bottle.png',
price = 11, -- what it sells for now, after random prices, before a sale
basePrice = 10, -- the price set by the admin or the owner
stock = 30, -- nil is unlimited
maxStock = 50, -- nil for unlimited and player-driven stock
playerStocked = false, -- player-driven stock
license = nil,
jobRestriction = nil,
metadata = nil,
buyEnabled = true, -- false: Sell only, never on a Buy tab
sellEnabled = true, -- false: Buy only, never on a Sell tab
sellPrice = nil, -- nil uses the shop's percentage
sellHidden = false,
autoRestockThreshold = nil,
autoRestockQuantity = nil,
catalogId = nil, -- set on listings made by Stock from catalogs
}A sale:
{
label = 'Grand Opening',
discountPct = 30,
listingIds = { 42, 43 }, -- nil for the whole shop
jobs = nil, -- { 'police', ... } when limited to jobs
startsAt = 1730000000, -- unix seconds
endsAt = 1730172800,
createdBy = 'ABC12345',
}local shop = exports.lation_shops:GetShop('24_7_store')
if shop and shop.ownerIdentifier then
print(('%s is owned by %s and holds %d'):format(shop.title, shop.ownerName, shop.balance))
endGetAllShops
Server export
local shops = exports.lation_shops:GetAllShops()Returns
table- Every shop keyed by shop ID, or an empty table
Each shop has the shape of GetShop, except that a listing's price is the price as set (no random prices) and it has no basePrice, maxStock or auto-restock fields. It reads every shop and listing, so use it for one-off lookups, not in a loop.
GetShopBalance
Server export
local balance = exports.lation_shops:GetShopBalance(shopId)Parameters
shopIdstring- The shop ID
Returns
number | nil- The balance, or
nilwhen there is no such shop
With bank accounts on, it is the account's balance.
GetShopOwner
Server export
local owner = exports.lation_shops:GetShopOwner(shopId)Parameters
shopIdstring- The shop ID
Returns
table | nil{ identifier, name, forSale, salePrice }, ornilwhen there is no such shop.identifierandnamearenilwhile the server runs it.
local owner = exports.lation_shops:GetShopOwner('24_7_store')
if owner and owner.identifier then
print(('24/7 is owned by %s'):format(owner.name))
elseif owner and owner.forSale then
print(('24/7 is for sale at %d'):format(owner.salePrice))
endGetOwnedShops
Server export
local shops = exports.lation_shops:GetOwnedShops(identifier)Parameters
identifierstring- The player's identifier
Returns
table- A list of the shops the player owns, each shaped like the shops of
GetAllShops. Shops they only work at are not included.
IsShopEmployee
Server export
local employed = exports.lation_shops:IsShopEmployee(shopId, identifier)Parameters
shopIdstring- The shop ID
identifierstring- The player's identifier
Returns
booleantrueonly for hired staff. The owner is not an employee: checkGetShopOwner.
GetShopEmployees
Server export
local employees = exports.lation_shops:GetShopEmployees(shopId)Parameters
shopIdstring- The shop ID
Returns
table- The staff, earliest hired first; empty when there are none
An employee:
{
identifier = 'XYZ98765',
name = 'Maria Lopez',
role = 'Manager',
permissions = { manage_inventory = true, place_orders = true, --[[ every permission key ]] },
commission = { default = 5, rules = { { type = 'item', key = 'burger', pct = 10 } }, mode = 'online' }, -- nil when none
earnings = 412, -- unclaimed
hiredBy = 'ABC12345',
}GetShopStats
Server export
local stats = exports.lation_shops:GetShopStats(shopId)Parameters
shopIdstring- The shop ID
Returns
table | nil- The figures the owner's dashboard shows (below), or
nilwhen there is no such shop
They cover the last 7 days, only the current owner's time with the shop, and are cached for 10 seconds:
{
today = 1240, -- revenue since midnight
week = 8630, -- revenue over the last 7 days
weekSellPayouts = 410, -- paid to customers for sell-backs
topSellers = {}, -- up to 6: { item_name, totalQuantity, totalAmount }
dailyRevenue = {}, -- 7 days, oldest first: { day = '2026-11-01', total }
dailySellPayouts = {}, -- the same, for sell-backs
dailyBalance = {}, -- the balance at the end of each day: { day, total }
}GetShopBankAccount
Server export
local accountId = exports.lation_shops:GetShopBankAccount(shopId)Parameters
shopIdstring- The shop ID
Returns
string | nilshop:<shopId>while shop balances are held at lation banking, otherwisenil
See bank accounts.
GetConfig
Server export
local section = exports.lation_shops:GetConfig(sectionId)Parameters
sectionIdstringoptionaldefaultnilgeneral,selling,transactions,ownership,employees,orders,salesorfinances
Returns
table | nil- A copy of the section's live values keyed by option id (
ownership.maxEmployees). With no section, every section but logging, keyed by section.logsand unknown sections returnnil.
The ids are on the configuration page.
local employees = exports.lation_shops:GetConfig('employees')
print(employees['ownership.maxEmployees']) -- 10Delivery exports
These finish a stock order when Config > Orders > Delivery system is custom. Call them from the server.
CompleteStockOrder
Server export
local applied = exports.lation_shops:CompleteStockOrder(orderId)Parameters
orderIdnumber- The order handed to
OnDeliveryRequested
Returns
booleantruewhen the stock landed,falsewhen the order is unknown or already delivered or cancelled
Applies the order's stock to the shop, once, the way the timer does: staff are told, open shops update, and orderDelivered fires.
CancelStockOrder
Server export
local cancelled = exports.lation_shops:CancelStockOrder(orderId)Parameters
orderIdnumber- The pending order
Returns
booleantruewhen it was cancelled,falsewhen the order is unknown or no longer pending
Cancels the order and refunds the shop at Config > Orders > Order cancellation refund (75% by default).
Custom delivery example
function OnDeliveryRequested(shopId, orderId, order, dropoff, pickup)
-- start your own delivery job with the order, its drop-off and pickup
exports.my_delivery:CreateJob({ id = orderId, shop = shopId, dropoff = dropoff, pickup = pickup })
end
function OnDeliveryCancelled(shopId, orderId)
-- the order was cancelled in the shop: drop your job
exports.my_delivery:RemoveJob(orderId)
end-- when the driver arrives
exports.lation_shops:CompleteStockOrder(orderId)
-- if your system gives up on the job
exports.lation_shops:CancelStockOrder(orderId)If OnDeliveryRequested throws an error, the order arrives on the timer instead.
Client exports
openShop (client)
Client export
exports.lation_shops:openShop(shopId)Parameters
shopIdstring- The shop to open
Opens the screen that matches the shop's mode: buy, sell, or both. The hours and the job requirement (and, for buy screens, the item requirement) are checked on the client first, with a notification on a refusal, then the server checks everything again. It does nothing before the player has loaded in.
The server still checks the player's distance to the shop, unless the shop has no locations (or a Model location), or Config > General > Trust client exports is on. A shop with no locations can be opened from anywhere this way, which suits a shop opened from a menu or a phone.
RegisterCommand('phoneshop', function()
exports.lation_shops:openShop('phone_store') -- a shop with no locations
end)openShopManagement
Client export
exports.lation_shops:openShopManagement(shopId)Parameters
shopIdstring- The shop to manage
Opens the management menu for a shop the player owns or works at, wherever they are. For any other shop it does nothing.
Events
lation shops fires these server events once a change is saved. They are local server events: listen with AddEventHandler, and clients can't fire them. Each one but configUpdated passes one table.
| Event | When |
|---|---|
lation_shops:purchase | A customer bought from a shop |
lation_shops:sale | A customer sold to a shop |
lation_shops:ownerChanged | A shop was bought, transferred, abandoned, assigned or repossessed |
lation_shops:employeeChanged | Staff hired, fired, or given a new role, permissions or commission |
lation_shops:balanceChanged | Any move of a shop balance |
lation_shops:orderPlaced | A stock order was placed |
lation_shops:orderPosted | An order was handed to a delivery system |
lation_shops:orderClaimed | A truck driver took an order |
lation_shops:orderCancelled | An order was cancelled |
lation_shops:orderDelivered | An order's stock landed |
lation_shops:shopUpdated | A shop was created or saved, or renamed by its owner |
lation_shops:shopDeleted | A shop was deleted |
lation_shops:configUpdated | The live configuration loaded or a section was saved |
A listener that throws doesn't break the shop, but listeners run in line. Purchases, sales, deposits and withdrawals fire inside a per-player lock, so a slow handler holds up that player's next transaction. Keep handlers fast and move heavy work to a SetTimeout or a queue.
lation_shops:purchase
Server event
AddEventHandler('lation_shops:purchase', function(data) end)data
shopIdstring- The shop
sourcenumber- The buyer's server id
identifierstring- The buyer's identifier
namestring- The buyer's character name
itemstable{ item, quantity, price }per line;priceis per unit, after any saletotalnumber- What the buyer paid
paymentMethodstring- The payment method's id:
cash,bank, a job name or a custom id shopRevenuenumber- What the shop kept, after revenue shares and commission
AddEventHandler('lation_shops:purchase', function(data)
print(('%s spent %d at %s'):format(data.name, data.total, data.shopId))
end)lation_shops:sale
Server event
AddEventHandler('lation_shops:sale', function(data) end)data
shopIdstring- The shop
sourcenumber- The seller's server id
identifierstring- The seller's identifier
namestring- The seller's character name
itemstable{ item, quantity, price }per line;priceis what the shop paid per unittotalnumber- What the seller received
paymentSourcetable | nil- The shop's selling setup:
{ type, account?, delivery, deliveryItem? }
AddEventHandler('lation_shops:sale', function(data)
if data.shopId == 'pawn_shop' and data.total > 5000 then
TriggerEvent('police:alert', ('Large sale at the pawn shop by %s'):format(data.name))
end
end)lation_shops:ownerChanged
Server event
AddEventHandler('lation_shops:ownerChanged', function(data) end)data
shopIdstring- The shop
reasonstringpurchase,transfer,abandon,adminAssignoradminRemoveownerIdentifierstring | nil- The new owner,
nilwhen nobody owns it now ownerNamestring | nil- The new owner's name
previousIdentifierstring | nil- The owner before
previousNamestring | nil- Their name
sourcenumber | nil- The player who made the change; absent on a transfer
An abandon or a repossession removes every employee without an employeeChanged for each; treat it as a full staff reset. A transfer keeps the staff.
AddEventHandler('lation_shops:ownerChanged', function(data)
if data.reason == 'purchase' then
print(('%s bought %s'):format(data.ownerName, data.shopId))
end
end)lation_shops:employeeChanged
Server event
AddEventHandler('lation_shops:employeeChanged', function(data) end)data
shopIdstring- The shop
actionstringhired,fired,updated(role or permissions) orcompensationidentifierstring- The employee
namestring- Their name
sourcenumber- The player who made the change
AddEventHandler('lation_shops:employeeChanged', function(data)
if data.action == 'hired' then
print(('%s now works at %s'):format(data.name, data.shopId))
end
end)lation_shops:balanceChanged
Server event
AddEventHandler('lation_shops:balanceChanged', function(data) end)data
shopIdstring- The shop
deltanumber | nil- How much moved, for a move in or out
balancenumber | nil- The new balance, when it was set outright
reasonstring | nil- Why:
sale_revenue,sell_payout,stock_order,order_refund,deposit,withdraw,withdraw_rollback,bonus,bonus_rollback,purchase_reset,shop_deleted(paid to the owner of a shop being deleted),bank(moved at lation banking) orbank_sync
It fires for every move, so it is the one to watch for a shop's money.
AddEventHandler('lation_shops:balanceChanged', function(data)
if data.delta and data.delta < -10000 then
print(('%s lost %d (%s)'):format(data.shopId, -data.delta, data.reason or '?'))
end
end)lation_shops:orderPlaced
Server event
AddEventHandler('lation_shops:orderPlaced', function(data) end)data
shopIdstring- The shop
orderIdnumber- The order
itemstable{ item, label, quantity, wholesaleEach }per linetotalCostnumber- The wholesale total, paid from the shop balance
identifierstring | nil- Who ordered;
nilfor an auto-restock namestring- Their name, or the auto-restock's
AddEventHandler('lation_shops:orderPlaced', function(data)
print(('order #%d for %s: %d'):format(data.orderId, data.shopId, data.totalCost))
end)lation_shops:orderPosted
Server event
AddEventHandler('lation_shops:orderPosted', function(data) end)data
shopIdstring- The shop
orderIdnumber- The order
systemstringm-TruckerSimulatororcustom
AddEventHandler('lation_shops:orderPosted', function(data)
print(('order #%d is on the %s board'):format(data.orderId, data.system))
end)lation_shops:orderClaimed
Server event
AddEventHandler('lation_shops:orderClaimed', function(data) end)data
shopIdstring- The shop
orderIdnumber- The order
driverany- The driver, as
m-TruckerSimulatorreports them
AddEventHandler('lation_shops:orderClaimed', function(data)
print(('order #%d for %s is in transit'):format(data.orderId, data.shopId))
end)lation_shops:orderCancelled
Server event
AddEventHandler('lation_shops:orderCancelled', function(data) end)data
shopIdstring- The shop
orderIdnumber- The order
refundnumber- What went back into the shop balance
sourcenumber | nil- The player who cancelled it by hand; absent for an abandon, a repossession, a deleted shop or
CancelStockOrder
AddEventHandler('lation_shops:orderCancelled', function(data)
print(('order #%d cancelled, %d refunded'):format(data.orderId, data.refund))
end)lation_shops:orderDelivered
Server event
AddEventHandler('lation_shops:orderDelivered', function(data) end)data
shopIdstring- The shop
orderIdnumber- The order
itemstable{ item, label, quantity, wholesaleEach }per line
AddEventHandler('lation_shops:orderDelivered', function(data)
print(('order #%d arrived at %s'):format(data.orderId, data.shopId))
end)lation_shops:shopUpdated
Server event
AddEventHandler('lation_shops:shopUpdated', function(data) end)data
shopIdstring- The shop
createdbooleantruethe first time it is savedsourcenumber- The admin who saved it, or the owner or staff member who renamed it or changed its hours
AddEventHandler('lation_shops:shopUpdated', function(data)
if data.created then
print(('new shop %s'):format(data.shopId))
end
end)lation_shops:shopDeleted
Server event
AddEventHandler('lation_shops:shopDeleted', function(data) end)data
shopIdstring- The shop
sourcenumber- The admin who deleted it
By then the shop has settled up: its orders on the way are cancelled (each fires orderCancelled), its staff are paid their unclaimed earnings and its owner the balance. See delete a shop.
AddEventHandler('lation_shops:shopDeleted', function(data)
print(('shop %s deleted'):format(data.shopId))
end)lation_shops:configUpdated
Server event
AddEventHandler('lation_shops:configUpdated', function(section) end)Parameters
sectionstring | nil- The section saved (
general,ownership, ...), ornilwhen the configuration first loads
Read the new values with GetConfig.
AddEventHandler('lation_shops:configUpdated', function(section)
if section == nil or section == 'employees' then
local employees = exports.lation_shops:GetConfig('employees')
print(('staff cap is now %d'):format(employees['ownership.maxEmployees']))
end
end)Hooks
server/utils/hooks.lua ships open. Its functions are empty or allow everything; fill in the ones you need.
A hook that decides must return true to allow. Returning nothing refuses, so a hook you fill in without a return true at the end turns the shop off.
OnBeforeShopOpen
Hook
function OnBeforeShopOpen(source, shopId, shop) return true endParameters
sourcenumber- The player's server id
shopIdstring- The shop
shoptable- The shop, shaped like
GetShop
Returns
boolean, string?trueto allow, orfalseand an optional message the player sees
Runs on every open, after the job check and before any item is taken for the item requirement, and again before every purchase and sale. It runs on the server only, so the shop's blips and prompts still show to everyone; only the open is refused.
-- A gang-only shop (Qbox)
function OnBeforeShopOpen(source, shopId, shop)
if shopId == 'ballas_stash' then
local player = exports.qbx_core:GetPlayer(source)
local gang = player and player.PlayerData.gang
if not gang or gang.name ~= 'ballas' then
return false, 'Members only'
end
end
return true
endOnBeforeItemPurchase
Hook
function OnBeforeItemPurchase(source, shopId, item, quantity, price, metadata, listingId, category) return true endParameters
sourcenumber- The buyer's server id
shopIdstring- The shop
itemstring- The item name
quantitynumber- How many
pricenumber- The price per unit, after any sale
metadatatable | nil- The listing's metadata
listingIdnumber- The listing
categorystring | nil- The listing's category
Returns
boolean, string?trueto allow, orfalseand an optional message shown on the cart line
Runs for each line at checkout, after the job, license and carry checks and before any stock is taken or money charged. One refusal stops the whole checkout.
function OnBeforeItemPurchase(source, shopId, item, quantity, price, metadata, listingId, category)
if item == 'advanced_rifle' and exports.xp_system:GetLevel(source) < 10 then
return false, 'You need level 10'
end
return true
endOnPurchaseItemMetadata
Hook
function OnPurchaseItemMetadata(source, shopId, item, quantity, price, metadata, listingId) return nil endParameters
sourcenumber- The buyer's server id
shopIdstring- The shop
itemstring- The item name
quantitynumber- How many
pricenumber- The price per unit
metadatatable | nil- The listing's metadata
listingIdnumber- The listing
Returns
table | nil- The metadata to give the item with, or
nilto keep the listing's
-- An ID card carries the buyer's details (Qbox)
function OnPurchaseItemMetadata(source, shopId, item, quantity, price, metadata, listingId)
if item == 'id_card' then
return exports.qbx_idcard:GetMetaLicense(source, 'id_card')
end
return nil
endOnBeforeItemSell
Hook
function OnBeforeItemSell(source, shopId, item, quantity, sellPrice, listingId) return true endParameters
sourcenumber- The seller's server id
shopIdstring- The shop
itemstring- The item name
quantitynumber- How many
sellPricenumber- What the shop pays per unit
listingIdnumber- The listing
Returns
boolean, string?trueto allow, orfalseand an optional message shown on the cart line
function OnBeforeItemSell(source, shopId, item, quantity, sellPrice, listingId)
if exports.my_evidence:IsStolen(source, item) then
return false, 'This shop won\'t take that'
end
return true
endOnDeliveryJob
Hook
function OnDeliveryJob(shopId, orderId, job) return nil endParameters
shopIdstring- The shop
orderIdnumber- The order
jobtable- The job as it will be posted to
m-TruckerSimulator(below)
Returns
table | nil- A job to post instead, or
nilto post it as built
The job:
{
id = 501, -- the order id
source = 'lation_shops',
pickup = { x, y, z, w }, -- nil: the trucking resource's depot
dropoff = { x, y, z, w },
reward = 1000,
company = '24/7 Store',
cargo = 'Shop stock',
metadata = { shopId = '24_7_store', items = { { name = 'burger', amount = 50 } } },
trailerModel = nil, -- optional
}A returned job missing its id, drop-off, a reward above 0, a company, cargo or metadata isn't posted; the order arrives on the timer instead.
function OnDeliveryJob(shopId, orderId, job)
job.trailerModel = 'trailers2'
job.reward = job.reward + 250
return job
endOnDeliveryRequested
Hook
function OnDeliveryRequested(shopId, orderId, order, dropoff, pickup) endParameters
shopIdstring- The shop
orderIdnumber- The order
ordertable{ orderId, shopId, items, totalCost, orderedBy, orderedByName, ... }, with each item{ item, label, quantity, wholesaleEach }dropofftable | nil{ x, y, z, w }, chosen as on delivery;nilfor a shop with no locations or drop-offspickuptable | nil{ x, y, z, w }, one of Config > Orders > Pickup warehouses, ornilwhen there are none
Called when an order needs delivering and the delivery system is custom. Finish it with CompleteStockOrder or CancelStockOrder; see the example. An error here sends the order to the timer.
Hooks that report
These run after something happened and their return value is ignored.
| Hook | Arguments | Called |
|---|---|---|
OnItemPurchased | source, shopId, item, quantity, price, metadata, listingId | After each line of a purchase is given |
OnItemSold | source, shopId, item, quantity, sellPrice, listingId | After each line of a sale is taken |
OnRevenueShared | shopId, society, amount, percentage | After a revenue share reached a job's account |
OnShopCreated | source, shopId, shopData | An admin created a shop |
OnShopEdited | source, shopId, shopData | An admin saved a shop |
OnShopDeleted | source, shopId | An admin deleted a shop |
OnShopPurchased | source, shopId, price | A player bought a shop |
OnShopSold | source, shopId, refund | An owner abandoned their shop |
OnEmployeeHired | source, shopId, employeeIdentifier | An employee was hired |
OnEmployeeFired | source, shopId, employeeIdentifier | An employee was fired |
OnBalanceWithdrawn | source, shopId, amount | Money was withdrawn from a shop |
OnBalanceDeposited | source, shopId, amount | Money was deposited into a shop |
OnStockOrderPlaced | source, shopId, orderId, totalCost | A stock order was placed; source is nil for an auto-restock |
OnStockOrderDelivered | shopId, orderId, items | An order's stock landed |
OnDeliveryCancelled | shopId, orderId | A posted delivery was withdrawn because its order was cancelled |
OnSaleCreated | source, shopId, sale | An owner started a sale; sale is shaped as on GetShop |
OnSaleEnded | shopId, sale | A sale was ended by hand or ran out |
OnStockDeposited | source, shopId, item, quantity | A member put items into stock |
OnStockWithdrawn | source, shopId, item, quantity | A member took stock |
OnBonusPaid | source, shopId, identifier, amount | The owner paid an employee a bonus |
OnEarningsClaimed | source, shopId, amount | A member claimed their earnings |
source is the server id of the player who did it.
Customizing systems
The interaction and notification systems, the bank, the framework and inventory calls, and who counts as an admin can each be replaced in an open file. See open files.
Still stuck? Ask in our Discord: the people who write the scripts answer.
Last updated