lation scripts
scriptsmembershipdocs
see the scripts
Skip to Content
lation ui
lation interact
lation banking
lation shops
Kinds of shopCreating shopsPlayer ownershipManagement menuStorefrontConfigurationDevelopersChangelog
lation jobs
lation weed
lation chop shop

classics

money laundering
drug sales
coke processing
meth crafting
metal detecting
scuba diving
lation shops

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

ExportReturns
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

boolean
true when the screen opened, false when 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.

server.lua
-- 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)))
end

Only 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 nil when 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',
}
server.lua
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))
end

GetAllShops

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 nil when 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 }, or nil when there is no such shop. identifier and name are nil while the server runs it.
server.lua
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))
end

GetOwnedShops

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

boolean
true only for hired staff. The owner is not an employee: check GetShopOwner.

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 nil when 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 | nil
shop:<shopId> while shop balances are held at lation banking, otherwise nil

See bank accounts.

GetConfig

Server export

local section = exports.lation_shops:GetConfig(sectionId)

Parameters

sectionIdstringoptionaldefault nil
general, selling, transactions, ownership, employees, orders, sales or finances

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. logs and unknown sections return nil.

The ids are on the configuration page.

server.lua
local employees = exports.lation_shops:GetConfig('employees')
print(employees['ownership.maxEmployees']) -- 10

Delivery 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

boolean
true when the stock landed, false when 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

boolean
true when it was cancelled, false when 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

server/utils/hooks.lua
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
my_delivery/server.lua
-- 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.

client.lua
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.

EventWhen
lation_shops:purchaseA customer bought from a shop
lation_shops:saleA customer sold to a shop
lation_shops:ownerChangedA shop was bought, transferred, abandoned, assigned or repossessed
lation_shops:employeeChangedStaff hired, fired, or given a new role, permissions or commission
lation_shops:balanceChangedAny move of a shop balance
lation_shops:orderPlacedA stock order was placed
lation_shops:orderPostedAn order was handed to a delivery system
lation_shops:orderClaimedA truck driver took an order
lation_shops:orderCancelledAn order was cancelled
lation_shops:orderDeliveredAn order's stock landed
lation_shops:shopUpdatedA shop was created or saved, or renamed by its owner
lation_shops:shopDeletedA shop was deleted
lation_shops:configUpdatedThe 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; price is per unit, after any sale
totalnumber
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
server.lua
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; price is what the shop paid per unit
totalnumber
What the seller received
paymentSourcetable | nil
The shop's selling setup: { type, account?, delivery, deliveryItem? }
server.lua
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
reasonstring
purchase, transfer, abandon, adminAssign or adminRemove
ownerIdentifierstring | nil
The new owner, nil when 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.

server.lua
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
actionstring
hired, fired, updated (role or permissions) or compensation
identifierstring
The employee
namestring
Their name
sourcenumber
The player who made the change
server.lua
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) or bank_sync

It fires for every move, so it is the one to watch for a shop's money.

server.lua
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 line
totalCostnumber
The wholesale total, paid from the shop balance
identifierstring | nil
Who ordered; nil for an auto-restock
namestring
Their name, or the auto-restock's
server.lua
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
systemstring
m-TruckerSimulator or custom
server.lua
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-TruckerSimulator reports them
server.lua
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
server.lua
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
server.lua
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
createdboolean
true the first time it is saved
sourcenumber
The admin who saved it, or the owner or staff member who renamed it or changed its hours
server.lua
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.

server.lua
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, ...), or nil when the configuration first loads

Read the new values with GetConfig.

server.lua
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 end

Parameters

sourcenumber
The player's server id
shopIdstring
The shop
shoptable
The shop, shaped like GetShop

Returns

boolean, string?
true to allow, or false and 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.

server/utils/hooks.lua
-- 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
end

OnBeforeItemPurchase

Hook

function OnBeforeItemPurchase(source, shopId, item, quantity, price, metadata, listingId, category) return true end

Parameters

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?
true to allow, or false and 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.

server/utils/hooks.lua
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
end

OnPurchaseItemMetadata

Hook

function OnPurchaseItemMetadata(source, shopId, item, quantity, price, metadata, listingId) return nil end

Parameters

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 nil to keep the listing's
server/utils/hooks.lua
-- 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
end

OnBeforeItemSell

Hook

function OnBeforeItemSell(source, shopId, item, quantity, sellPrice, listingId) return true end

Parameters

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?
true to allow, or false and an optional message shown on the cart line
server/utils/hooks.lua
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
end

OnDeliveryJob

Hook

function OnDeliveryJob(shopId, orderId, job) return nil end

Parameters

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 nil to 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.

server/utils/hooks.lua
function OnDeliveryJob(shopId, orderId, job)
    job.trailerModel = 'trailers2'
    job.reward = job.reward + 250
    return job
end

OnDeliveryRequested

Hook

function OnDeliveryRequested(shopId, orderId, order, dropoff, pickup) end

Parameters

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; nil for a shop with no locations or drop-offs
pickuptable | nil
{ x, y, z, w }, one of Config > Orders > Pickup warehouses, or nil when 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.

HookArgumentsCalled
OnItemPurchasedsource, shopId, item, quantity, price, metadata, listingIdAfter each line of a purchase is given
OnItemSoldsource, shopId, item, quantity, sellPrice, listingIdAfter each line of a sale is taken
OnRevenueSharedshopId, society, amount, percentageAfter a revenue share reached a job's account
OnShopCreatedsource, shopId, shopDataAn admin created a shop
OnShopEditedsource, shopId, shopDataAn admin saved a shop
OnShopDeletedsource, shopIdAn admin deleted a shop
OnShopPurchasedsource, shopId, priceA player bought a shop
OnShopSoldsource, shopId, refundAn owner abandoned their shop
OnEmployeeHiredsource, shopId, employeeIdentifierAn employee was hired
OnEmployeeFiredsource, shopId, employeeIdentifierAn employee was fired
OnBalanceWithdrawnsource, shopId, amountMoney was withdrawn from a shop
OnBalanceDepositedsource, shopId, amountMoney was deposited into a shop
OnStockOrderPlacedsource, shopId, orderId, totalCostA stock order was placed; source is nil for an auto-restock
OnStockOrderDeliveredshopId, orderId, itemsAn order's stock landed
OnDeliveryCancelledshopId, orderIdA posted delivery was withdrawn because its order was cancelled
OnSaleCreatedsource, shopId, saleAn owner started a sale; sale is shaped as on GetShop
OnSaleEndedshopId, saleA sale was ended by hand or ran out
OnStockDepositedsource, shopId, item, quantityA member put items into stock
OnStockWithdrawnsource, shopId, item, quantityA member took stock
OnBonusPaidsource, shopId, identifier, amountThe owner paid an employee a bonus
OnEarningsClaimedsource, shopId, amountA 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 November 10, 2026

Configuration

Every server-wide lation shops option with its default and range, edited live under /shopadmin > Config since the resource has no config file, plus language, theme, commands and open files.

Changelog

Every lation shops release, newest first, with what it added, changed and fixed.

On this page

Server exportsopenShopGetShopGetAllShopsGetShopBalanceGetShopOwnerGetOwnedShopsIsShopEmployeeGetShopEmployeesGetShopStatsGetShopBankAccountGetConfigDelivery exportsCompleteStockOrderCancelStockOrderCustom delivery exampleClient exportsopenShop (client)openShopManagementEventslation_shops:purchaselation_shops:salelation_shops:ownerChangedlation_shops:employeeChangedlation_shops:balanceChangedlation_shops:orderPlacedlation_shops:orderPostedlation_shops:orderClaimedlation_shops:orderCancelledlation_shops:orderDeliveredlation_shops:shopUpdatedlation_shops:shopDeletedlation_shops:configUpdatedHooksOnBeforeShopOpenOnBeforeItemPurchaseOnPurchaseItemMetadataOnBeforeItemSellOnDeliveryJobOnDeliveryRequestedHooks that reportCustomizing systems
lation scripts

FiveM scripts for Qbox, QBCore and ESX servers, made to look and work like one product.

store

  • all scripts
  • membership
  • classics

help

  • docs
  • discord
  • email support

legal

  • terms
  • refunds
  • privacy
© 2026 Lation Labslationscripts.com
  • home
  • scripts
  • membership
  • docs