Client events
Client events fire on one player’s game: the buyer, the seller, the bidder who was outbid, the robber… They are never broadcast to everyone. Listen to them in client/handlers.lua (the handlers are already there, empty) or from any client script of your own:
AddEventHandler('sl-marketplace:onSaleMade', function(data) PlaySoundFrontend(-1, 'WAYPOINT_SET', 'HUD_FRONTEND_DEFAULT_SOUNDSET', true)end)Summary
Section titled “Summary”| Event | Who receives it | Server hook with the same moment |
|---|---|---|
onPurchaseCompleted |
Buyer | OnSaleCompleted |
onSaleMade |
Seller (if online) | OnSaleCompleted |
onAuctionWon |
Winner (if online) | OnAuctionEnded |
onListingCreated |
Seller | OnListingCreated |
onListingCancelled |
Seller | OnListingCancelled |
onListingBumped |
Seller | OnListingBumped |
onBidPlaced |
Bidder | OnBidPlaced |
onOutbid |
Player who was outbid | OnBidPlaced |
onMailboxClaimed |
Player collecting | OnMailboxClaimed |
onMessageReceived |
Recipient of a chat message | OnMessageSent |
onRefundStatusChanged |
Buyer and seller | OnRefundRequested / Approved / Rejected |
onDeliveryArrived |
Buyer | OnDeliveryCompleted |
onDeliveryResult |
Buyer | OnDeliveryCompleted / Failed / Robbed |
onDeliveryRobbed |
Robber | OnDeliveryRobbed |
onInPersonTradeStarted |
Buyer and seller | — |
onInPersonMeetUpdated |
Buyer and seller | OnMeetupStatusChanged |
onInPersonTradeCompleted |
Buyer and seller | OnInPersonTradeCompleted |
onInPersonTradeCancelled |
Buyer and seller | OnInPersonTradeCancelled |
onSkillCheckStarted |
Player doing the minigame | — |
onSkillCheckPhase |
Player doing the minigame | — |
onSkillCheckFinished |
Player doing the minigame | — |
All names start with sl-marketplace:, e.g. sl-marketplace:onSaleMade.
Purchases and sales
Section titled “Purchases and sales”onPurchaseCompleted
Section titled “onPurchaseCompleted”Who: the buyer. When: right after paying (OnSaleCompleted). For courier and in-person purchases settlementPending is true: the item has not arrived yet.
| Field | Meaning |
|---|---|
item, itemLabel, quantity |
What was bought |
price / basePrice |
Listing price, without extras |
grossPaid |
Total paid |
platformFee, deliveryFee, insuranceFee |
Fees |
deliveryMode, listingType, sellerName |
Details |
stage, settlementPending |
'committed' / true for courier and in person, 'settled' / false otherwise |
listingId |
Listing ID |
Example
AddEventHandler('sl-marketplace:onPurchaseCompleted', function(data) PlaySoundFrontend(-1, 'PURCHASE', 'HUD_LIQUOR_STORE_SOUNDSET', true)end)Test: buy any listing (solo: /markettest listing mailbox fixed bread 50).
onSaleMade
Section titled “onSaleMade”Who: the seller, only if online. When: one of their listings is bought.
| Field | Meaning |
|---|---|
buyerName |
Buyer |
item, itemLabel, quantity |
What was sold |
price / basePrice, grossPaid, platformFee, sellerPayout |
Money |
deliveryMode, listingType |
Details |
stage, settlementPending |
As in onPurchaseCompleted |
listingId |
Listing ID |
Test: two players; B buys one of A’s listings while A is online.
onAuctionWon
Section titled “onAuctionWon”Who: the winner, only if online. When: an auction they lead ends (OnAuctionEnded), up to 30 s after the end time.
| Field | Meaning |
|---|---|
item, itemLabel, quantity |
What they won |
winningBid / grossPrice / finalPrice |
Winning bid |
platformFee, sellerPayout |
Money |
sellerName, listingType, deliveryMode, meetupPoint |
Details |
stage |
'settled' |
listingId |
Listing ID |
Test: /markettest listing mailbox auction bread 100, bid, wait 5 minutes.
Listings and bids
Section titled “Listings and bids”onListingCreated
Section titled “onListingCreated”Who: the seller. When: their listing has been published.
Fields: listingId, item, itemLabel, itemMetadata, quantity, price, listingType, deliveryMode, featured.
Test: publish any item from the marketplace.
onListingCancelled
Section titled “onListingCancelled”Who: the seller. When: their listing is cancelled, by them or by an admin.
Fields: listingId, item, itemLabel, quantity, price, listingType, cancellationType ('owner' or 'admin').
Test: cancel one of your listings.
onListingBumped
Section titled “onListingBumped”Who: the seller. When: they bump a listing.
Fields: listingId, item, itemLabel, cost, bumpedAt.
Test: bump one of your listings.
onBidPlaced
Section titled “onBidPlaced”Who: the bidder. When: their bid is accepted, or proxy bidding bids for them automatically (bidType = 'proxy_auto').
Fields: listingId, item, itemLabel, amount, previousBid, bidType, sellerName.
Test: bid on a test auction.
onOutbid
Section titled “onOutbid”Who: the player who was leading. When: someone places a higher bid (by hand or by proxy).
| Field | Meaning |
|---|---|
listingId, item, itemLabel |
The auction |
previousBid |
Their bid, now beaten |
newBid |
The new highest bid |
bidderName |
Who beat them |
bidType |
'manual' or 'proxy_auto' |
Example: sound and screen flash
AddEventHandler('sl-marketplace:onOutbid', function(data) PlaySoundFrontend(-1, 'LOSER', 'HUD_AWARDS', true) AnimpostfxPlay('FocusOut', 800, false)end)Test: two players bid on the same auction; the first one gets onOutbid when the second bids more.
Mailbox, chat and refunds
Section titled “Mailbox, chat and refunds”onMailboxClaimed
Section titled “onMailboxClaimed”Who: the player. When: they collect something from their mailbox.
Fields: mailboxId, claimType ('item' or 'money'), amount, item, itemLabel, itemMetadata, quantity, meetupPoint, reason.
Test: collect anything from your mailbox (a won auction always ends up there).
onMessageReceived
Section titled “onMessageReceived”Who: the recipient. When: they receive a message in a listing’s chat.
| Field | Meaning |
|---|---|
listingId |
Listing of the conversation |
conversationKey |
Conversation ID |
fromIdentifier, partnerIdentifier |
Sender and the other side of the chat |
messageId |
Message ID |
messageKind |
Kind of message |
preview |
Short preview of the text |
Example: phone-style notification when the marketplace is closed
AddEventHandler('sl-marketplace:onMessageReceived', function(data) exports['okokNotify']:Alert('Marketplace', data.preview, 4000, 'info')end)Test: two players; B writes to A from one of A’s listings.
onRefundStatusChanged
Section titled “onRefundStatusChanged”Who: buyer and seller (each gets their own role). When: a refund is requested, approved, forced or rejected.
| Field | Meaning |
|---|---|
refundId, historyId, listingId |
IDs |
role |
'buyer' or 'seller' |
status |
'pending', 'approved', 'forced' or 'rejected' |
item, itemLabel, amount |
What and how much |
reason / note |
Buyer’s reason or seller’s note |
Test: two players; B requests a refund on a purchase from A, A approves or rejects it.
NPC delivery
Section titled “NPC delivery”onDeliveryArrived
Section titled “onDeliveryArrived”Who: the buyer. When: the courier van hands them the item. Does not fire if the van was robbed or failed.
Fields: deliveryId, item, itemLabel, quantity, sellerName, listingId, deliveryMode, stage.
Test: /markettest listing npc fixed bread 50, buy it and wait for the van.
onDeliveryResult
Section titled “onDeliveryResult”Who: the buyer. When: a courier delivery ends, whatever the outcome. Use this one if you want a single handler for every case.
| Field | Meaning |
|---|---|
deliveryId, listingId |
IDs |
result |
'delivered', 'stolen' or 'failed' |
item, itemLabel, quantity, sellerName |
The order |
deliveryMode, stage |
Details |
reason |
Why it failed (only failed) |
refundAmount |
Refunded, when there was a refund |
thiefName |
Who robbed it (only stolen) |
Example
AddEventHandler('sl-marketplace:onDeliveryResult', function(data) if data.result == 'stolen' then exports['okokNotify']:Alert('Courier', data.thiefName .. ' robbed your package!', 6000, 'error') endend)Test: as onDeliveryArrived for delivered; destroy the van for failed; have another player rob it for stolen.
onDeliveryRobbed
Section titled “onDeliveryRobbed”Who: the robber. When: they rob a courier van (OnDeliveryRobbed).
Fields: deliveryId, item, itemLabel, itemMetadata, quantity, value, trigger ('cargo_stolen' or 'driver_killed'), listingId, stage.
Test: two players; one buys with courier delivery, the other robs the van.
In-person trades
Section titled “In-person trades”onInPersonTradeStarted
Section titled “onInPersonTradeStarted”Who: buyer and seller. When: an in-person trade is created, and again when a player reconnects with a trade still open (rehydrated = true).
| Field | Meaning |
|---|---|
tradeId (also id) |
Trade ID |
role |
'buyer' or 'seller' |
counterpart, partnerIdentifier |
The other player |
itemLabel, quantity, price, listingId |
The deal |
meetStatus |
State of the meeting point |
rehydrated |
true when restored after reconnecting |
Test: two players online; B buys one of A’s listings with the in person mode.
onInPersonMeetUpdated
Section titled “onInPersonMeetUpdated”Who: buyer and seller. When: the meeting point is proposed, accepted, declined, cancelled or expires.
Fields: tradeId (also id), meetStatus, meetProposedBy, meetProposedCoords, meetProposedAt, meetWindowEndsAt, meetCoords.
Test: in an in-person trade, propose a location from the chat and accept it with the other player.
onInPersonTradeCompleted
Section titled “onInPersonTradeCompleted”Who: buyer and seller. When: both confirm the exchange face to face.
Fields: tradeId, role, item (nil for barter), itemLabel, quantity (nil for barter), price (0 for barter), isBarter, tradeKind, barter, platformFee, sellerPayout, listingId, stage.
Test: complete an in-person trade.
onInPersonTradeCancelled
Section titled “onInPersonTradeCancelled”Who: buyer and seller. When: the trade is cancelled or times out.
Fields: tradeId (also id), reason, partnerIdentifier.
Test: cancel an in-person trade from the chat.
Skill check (robbery minigame)
Section titled “Skill check (robbery minigame)”The ring the robber has to time to force a van’s cargo hold. Three phases, each faster and on a different key (configured in Config.SkillCheck). context is currently always 'deliveryRobbery'.
onSkillCheckStarted
Section titled “onSkillCheckStarted”When: the ring appears, before the first phase.
Fields: context, deliveryId, phases (how many phases).
onSkillCheckPhase
Section titled “onSkillCheckPhase”When: each phase resolves.
| Field | Meaning |
|---|---|
context, deliveryId |
What is being attempted |
phase |
Phase that just resolved (1, 2, 3…) |
phases |
Total phases |
key |
Key the phase asked for ('E', 'Q', 'R', 'F') |
result |
'hit' or 'miss' |
onSkillCheckFinished
Section titled “onSkillCheckFinished”When: the minigame ends, however it ends. Always after the last onSkillCheckPhase.
| Field | Meaning |
|---|---|
context, deliveryId |
What was attempted |
result |
'passed' (all phases), 'failed' (a phase missed) or 'cancelled' (walked off, shot, or the van left) |
passed |
true only for 'passed' |
cleared |
Phases cleared before it ended |
phases |
Total phases |
Example: your own sounds instead of the built-in ones
Set Config.SkillCheck.Sounds = false and play your own:
AddEventHandler('sl-marketplace:onSkillCheckPhase', function(data) if data.result == 'hit' then PlaySoundFrontend(-1, 'CONFIRM_BEEP', 'HUD_MINI_GAME_SOUNDSET', true) else PlaySoundFrontend(-1, 'ERROR', 'HUD_FRONTEND_DEFAULT_SOUNDSET', true) endend)
AddEventHandler('sl-marketplace:onSkillCheckFinished', function(data) if data.result == 'failed' then -- a botched attempt makes noise: alert police from the SERVER, not from here TriggerServerEvent('your_dispatch:suspicious', 'Noise at a courier van') endend)Test the three: two players; one buys with courier delivery, the other intercepts the van, threatens the driver and starts forcing the cargo hold. Fail one run on purpose to see miss and failed.