Server hooks
Lifecycle hooks live in server/handlers.lua and are named Handlers.On…. They run after something has happened and cannot undo it; their return value is ignored. Every data table also has hook, timestamp, schemaVersion and resource (details).
Summary
Section titled “Summary”| Area | Hooks |
|---|---|
| Sales and auctions | OnSaleCompleted, OnAuctionEnded, OnReverseOfferAccepted |
| Listings | OnListingCreated, OnListingExpired, OnListingCancelled, OnListingBumped |
| Bids | OnBidPlaced, OnProxyBidSet |
| NPC delivery | OnDeliveryCompleted, OnDeliveryFailed, OnDeliveryRobbed |
| In-person trades and barter | OnInPersonTradeCompleted, OnInPersonTradeCancelled, OnMeetupStatusChanged, OnBarterProposalCreated, OnBarterProposalStatusChanged |
| Refunds | OnRefundRequested, OnRefundApproved, OnRefundRejected |
| Social | OnPlayerRated, OnMessageSent, OnFavoriteChanged, OnFollowChanged, OnWishlistChanged, OnReportCreated |
| Profile and mailbox | OnProfileCreated, OnProfileUpdated, OnMailboxClaimed |
| Administration | OnAdminAction |
| config.lua callbacks | Config.Notify, Config.OnDeliveryRobbed |
Sales and auctions
Section titled “Sales and auctions”OnSaleCompleted
Section titled “OnSaleCompleted”When: a buyer pays for a fixed-price listing, a bundle, a Dutch auction, or uses Buy Now on an auction. It fires as soon as the payment is committed.
What happens next depends on the delivery mode, told by data.deliveryMode and data.stage:
deliveryMode |
stage |
settlementPending |
What happens next |
|---|---|---|---|
'mailbox' |
'settled' |
false |
The item is already in the buyer’s inventory (or in their marketplace mailbox if it did not fit). Nothing else fires |
'meetup' |
'settled' |
false |
The item waits in the buyer’s mailbox, to be collected at the meetup point. Nothing else fires |
'npc' |
'committed' |
true |
A courier van is dispatched. OnDeliveryCompleted, OnDeliveryFailed or OnDeliveryRobbed fires later |
'person' |
'committed' |
true |
An in-person trade is created (the seller must be online, or the purchase is refused). OnInPersonTradeCompleted or OnInPersonTradeCancelled fires later |
| Field | Meaning |
|---|---|
buyerSource, buyerId, buyerName |
The buyer |
sellerSource, sellerId, sellerName |
The seller (sellerSource is nil if offline) |
item, itemLabel, itemMetadata, quantity |
What was sold |
category, rarity |
Category and rarity |
basePrice |
Listing price paid (after discounts), without extras |
grossPaid |
Total paid by the buyer |
platformFee, deliveryFee, modeSurcharge, npcDeliveryFee, insuranceFee |
Fees and extras (money fields) |
sellerPayout |
What the seller receives |
price |
Old alias of basePrice |
deliveryMode |
'mailbox', 'meetup', 'npc' or 'person' |
listingType |
'fixed', 'auction' (Buy Now), 'dutch' or 'bundle' |
stage, settlementPending |
See the table above |
listingId |
Listing ID |
Example: XP for the seller when the sale is final
Handlers.OnSaleCompleted = function(data) if data.settlementPending then return end -- courier / in person: wait for the final hook TriggerEvent('yourxp:addXP', data.sellerId, math.floor(data.basePrice / 100))endHow to test
- With the logger on,
Config.Debug = true, run/markettest listing mailbox fixed bread 50. - Give yourself money if needed:
/markettest grant 1000. - Open the marketplace and buy the Test item: bread listing.
- The console shows
OnSaleCompletedwithdeliveryMode = mailbox,stage = settled. - Repeat with
/markettest listing npc fixed bread 50to seestage = committedandsettlementPending = true.
OnAuctionEnded
Section titled “OnAuctionEnded”When: an ascending or blind auction reaches its end time with at least one bid. The script checks for finished auctions every 30 seconds, so it can fire up to 30 s after the end time. The item has already been sent to the winner’s mailbox (or to the meetup point) and the money to the seller’s mailbox.
An auction that ends with no bids fires OnListingExpired instead.
| Field | Meaning |
|---|---|
winnerSource, winnerId, winnerName |
Highest bidder |
sellerSource, sellerId, sellerName |
The seller |
item, itemLabel, itemMetadata, category, rarity, quantity |
The item |
winningBid / grossPrice |
Winning bid |
platformFee, sellerPayout |
Fee and what the seller receives |
finalPrice |
Old alias of sellerPayout |
listingType |
'auction' or 'blind' |
deliveryMode, meetupPoint |
How the winner collects it |
stage |
'settled' |
listingId |
Listing ID |
Example: announce big auctions in chat
Handlers.OnAuctionEnded = function(data) if data.winningBid >= 100000 then TriggerClientEvent('chat:addMessage', -1, { args = { 'Auction house', ('%s won %s for $%s'):format(data.winnerName, data.itemLabel, data.winningBid) } }) endendHow to test
/markettest listing mailbox auction bread 100creates a test auction that ends in 5 minutes.- Bid on it from your account.
- Wait 5 minutes (plus up to 30 s). The console shows
OnAuctionEndedand your client getssl-marketplace:onAuctionWon.
OnReverseOfferAccepted
Section titled “OnReverseOfferAccepted”When: in a reverse auction (a buyer posts “I’m looking for X, up to $Y”), the buyer accepts one of the sellers’ offers. The seller’s item goes to the buyer, the seller is paid and the rest of the buyer’s deposit is returned.
| Field | Meaning |
|---|---|
buyerSource, buyerId, buyerName |
Author of the request (the one paying) |
sellerSource, sellerId, sellerName |
The seller whose offer was accepted |
item, itemLabel, itemMetadata, quantity |
The item |
grossPrice |
Accepted offer |
platformFee, sellerPayout |
Fee and what the seller receives |
depositRefund |
Part of the deposit returned to the buyer |
messageId, listingId |
The offer and the request |
stage |
'settled' |
How to test: two players. A creates a reverse listing; B sends an offer from the listing; A accepts it. CanBuyListing also runs first with action = 'accept_reverse_offer'.
Listings
Section titled “Listings”OnListingCreated
Section titled “OnListingCreated”When: a listing of any type has been published (the item is already out of the seller’s inventory). The seller’s client also gets sl-marketplace:onListingCreated.
| Field | Meaning |
|---|---|
sellerSource, sellerId, sellerName |
The seller |
item, itemLabel, itemKind, itemMetadata, category, rarity, quantity |
The item |
price / basePrice |
Price or starting price |
buyNowPrice |
Buy Now price, or nil |
listingType |
'fixed', 'auction', 'blind', 'dutch', 'reverse', 'bundle' or 'barter' |
deliveryMode, deliveryModes, meetupPoint |
Delivery options |
featured, featuredCost |
Whether it was featured and the cost |
expiresAt |
End time (Unix seconds), or nil for listings that do not expire |
images, bundleItems, wantedItems, wantsAny |
Extra content |
listingId |
New listing ID |
Example: log featured listings
Handlers.OnListingCreated = function(data) if data.featured then print(('[market] %s paid $%d to feature %s'):format(data.sellerName, data.featuredCost, data.itemLabel)) endendHow to test: open the marketplace, publish any item and check the console.
OnListingExpired
Section titled “OnListingExpired”When: a listing with an end time reaches it without being sold. The check runs every 30 seconds.
Only these listing types expire: auction and blind auction without bids, Dutch auction, reverse auction and barter. Fixed-price listings and bundles never expire.
listingType |
What the script does | returnMode |
|---|---|---|
'auction', 'blind' (no bids) |
Item back to the seller’s mailbox | 'mailbox' |
'dutch' |
Item back to the seller’s mailbox | 'mailbox' |
'barter' |
Item back to the seller; every open proposal is rejected and its items and money returned | 'mailbox' |
'reverse' |
The buyer’s deposit is returned (if Config.Auctions.Reverse.DepositRequired) |
'deposit_refund' or 'none' |
| Field | Meaning |
|---|---|
sellerSource, sellerId, sellerName |
Owner of the listing |
item, itemLabel, itemMetadata, category, rarity, quantity |
The item |
price / basePrice |
Listing price |
listingType |
Type (see above) |
deliveryMode, meetupPoint |
Delivery options |
reason |
Currently always 'timeout' |
returnMode |
See above |
expiredAt |
When it expired (Unix seconds) |
listingId |
Listing ID |
How to test: /markettest listing mailbox auction bread 100 and don’t bid. After 5 minutes (plus up to 30 s) the console shows OnListingExpired with returnMode = mailbox.
OnListingCancelled
Section titled “OnListingCancelled”When: a listing is cancelled, by its owner or by an admin from the panel. The item is returned to the seller.
| Field | Meaning |
|---|---|
actorSource, actorId, actorName |
Who cancelled it |
sellerSource, sellerId, sellerName |
Owner of the listing |
item, itemLabel, itemMetadata, quantity, price |
The listing |
listingType |
Type |
cancellationType |
'owner' or 'admin' |
listingId |
Listing ID |
An owner cancellation first passes CanCancelListing; an admin cancellation also fires OnAdminAction with action = 'force_cancel'.
How to test: publish something and cancel it (cancellationType = 'owner'). Then publish again and cancel it from /marketadmin ('admin').
OnListingBumped
Section titled “OnListingBumped”When: a seller pays Config.BumpCost to push one of their listings back to the top of the results. Limited to once every 5 minutes (Config.RateLimits.bump).
| Field | Meaning |
|---|---|
sellerSource, sellerId, sellerName |
The seller |
item, itemLabel, quantity |
The listing |
cost |
Amount paid |
bumpedAt |
When (Unix seconds) |
listingId |
Listing ID |
How to test: bump one of your listings from the marketplace.
OnBidPlaced
Section titled “OnBidPlaced”When: a bid is accepted on an auction. It fires for bids placed by hand (bidType = 'manual') and for automatic bids placed by proxy bidding on someone’s behalf (bidType = 'proxy_auto').
| Field | Meaning |
|---|---|
bidderSource, bidderId, bidderName |
Who bid |
sellerId, sellerName |
The seller |
item, itemLabel |
The item |
amount |
New bid |
previousBid |
Previous highest bid |
bidType |
'manual' or 'proxy_auto' |
listingType |
'auction' or 'blind' |
listingId |
Listing ID |
Example: warn staff about suspicious jumps
Handlers.OnBidPlaced = function(data) if data.previousBid and data.previousBid > 0 and data.amount > data.previousBid * 10 then print(('[market] big jump on #%d: %d -> %d by %s'):format(data.listingId, data.previousBid, data.amount, data.bidderName)) endendHow to test: bid on a test auction (/markettest listing mailbox auction bread 100). To see proxy_auto, a second player sets a proxy maximum and you then outbid them.
OnProxyBidSet
Section titled “OnProxyBidSet”When: a player sets or changes their maximum for proxy bidding (Config.Auctions.ProxyBidding.Enabled). The script will bid for them automatically up to that amount.
| Field | Meaning |
|---|---|
bidderSource, bidderId, bidderName |
The player |
sellerId, sellerName |
The seller |
maxAmount |
Their maximum |
minimumBid |
Minimum valid bid when it was set |
listingId |
Listing ID |
How to test: open a test auction and set a proxy maximum instead of a normal bid.
NPC delivery
Section titled “NPC delivery”OnDeliveryCompleted
Section titled “OnDeliveryCompleted”When: a courier van reaches the buyer and hands over the item; the seller is paid now. This is the final moment of an NPC sale. The buyer’s client also gets sl-marketplace:onDeliveryArrived and sl-marketplace:onDeliveryResult (result = 'delivered').
| Field | Meaning |
|---|---|
deliveryId |
Delivery ID |
buyerSource, buyerId, buyerName |
The buyer |
sellerSource, sellerId, sellerName |
The seller |
item, itemLabel, itemMetadata, quantity |
The item |
basePrice, grossPaid, platformFee, deliveryFee, modeSurcharge, npcDeliveryFee, insuranceFee, sellerPayout |
Money fields |
price |
Old alias of sellerPayout |
deliveryMode, stage |
'npc', final stage |
listingId |
Listing ID |
How to test: /markettest listing npc fixed bread 50, buy it and wait for the van (about 1–2 minutes with the default MinDistance / MaxDistance).
OnDeliveryFailed
Section titled “OnDeliveryFailed”When: a courier delivery ends without the item being delivered (and without being robbed). The buyer is refunded automatically.
reason |
Cause |
|---|---|
'timeout' |
The van did not arrive within Config.Gameplay.NPCDelivery.DeliveryTimeout (600 s by default) |
'buyer_offline' |
The buyer left the server during the delivery |
'destroyed' |
The van was destroyed |
'unknown' |
Any other failure |
| Field | Meaning |
|---|---|
deliveryId |
Delivery ID |
buyerSource, buyerId, buyerName, sellerSource, sellerId, sellerName |
The players |
item, itemLabel, itemMetadata, quantity |
The item |
price / basePrice, grossPaid |
What was charged |
refundAmount |
Refunded to the buyer |
deliveryFee, modeSurcharge, npcDeliveryFee, insuranceFee |
Extras |
deliveryMode, stage, reason, listingId |
Details |
How to test: buy an NPC test listing and, while the van is on its way, destroy it (destroyed) or disconnect (buyer_offline). For timeout, temporarily set DeliveryTimeout = 30 and block the van’s road.
OnDeliveryRobbed
Section titled “OnDeliveryRobbed”When: another player robs a courier van: they force the cargo hold (the timing minigame) or, if Config.Gameplay.NPCDelivery.PoliceAlertOnKill is true, they kill the driver. It fires once per delivery, for whichever happens first. Config.OnDeliveryRobbed runs just before it. The robber’s client gets sl-marketplace:onDeliveryRobbed.
| Field | Meaning |
|---|---|
deliveryId |
Delivery ID |
thiefSource, thiefId, thiefName |
The robber |
buyerId, sellerId |
Buyer and seller |
item, itemLabel, itemMetadata, quantity |
Cargo |
value |
Value of the cargo |
trigger |
'cargo_stolen' or 'driver_killed' |
stage |
'robbed' |
listingId |
Listing ID |
Example: police dispatch
Handlers.OnDeliveryRobbed = function(data) local coords = GetEntityCoords(GetPlayerPed(data.thiefSource)) TriggerEvent('your_dispatch:alert', { code = '10-90', message = 'Courier van robbery', coords = coords, job = 'police' })endHow to test: two players. Player B buys an NPC listing (/markettest listing npc fixed bread 50); player A intercepts the van, threatens the driver and clears the minigame on the cargo hold. The order must be worth at least MinValueForIntercept.
In-person trades and barter
Section titled “In-person trades and barter”OnInPersonTradeCompleted
Section titled “OnInPersonTradeCompleted”When: both players have confirmed the exchange face to face, for a sale with the in person delivery mode or a barter. This is when items and money actually change hands. Both clients get sl-marketplace:onInPersonTradeCompleted.
| Field | Meaning |
|---|---|
tradeId |
Trade ID |
buyerSource, buyerId, buyerName, sellerSource, sellerId, sellerName |
The players |
item, itemLabel, quantity |
The item (nil for barter) |
price / basePrice |
Price (0 for barter) |
grossPaid, platformFee, sellerPayout |
Money |
isBarter, tradeKind |
true / 'barter' or false / 'person' |
barter |
What each side gave, for barter trades |
stage |
'settled' |
listingId |
Listing ID |
How to test: two players, both online. B buys A’s listing choosing in person, they agree a meeting point in the chat, meet there and both confirm (CanConfirmInPersonTrade runs for each one).
OnInPersonTradeCancelled
Section titled “OnInPersonTradeCancelled”When: an in-person or barter trade is cancelled: by either player, because one of them left the meeting area for more than AbandonTimeoutSeconds, or because TimeoutMinutes passed. Both are refunded automatically.
| Field | Meaning |
|---|---|
tradeId |
Trade ID |
buyerSource, buyerId, buyerName, sellerSource, sellerId, sellerName |
The players |
item, itemLabel, quantity, price / basePrice |
The deal |
isBarter, tradeKind, stage |
Details |
reason |
Why, as text (for example a timeout or who cancelled it) |
listingId |
Listing ID |
How to test: start an in-person trade as above and cancel it from the chat.
OnMeetupStatusChanged
Section titled “OnMeetupStatusChanged”When: the meeting point of an in-person trade changes state in the chat.
status |
Meaning |
|---|---|
'proposed' |
A player proposed a location |
'accepted' |
The other player accepted it (the blip and prompts appear) |
'declined' |
The other player declined it |
'cancelled' |
The author withdrew it |
'expired' |
Nobody answered within MeetRequestTimeoutSeconds (300 s) |
| Field | Meaning |
|---|---|
actorSource, actorId, actorName |
Who changed it |
partnerSource, partnerId |
The other player |
status |
See above |
tradeIds |
Trades covered by this meeting |
coords |
Proposed location |
windowEndsAt |
When the meeting window closes |
How to test: in an in-person trade, propose a location from the chat, then accept it or decline it with the other player.
OnBarterProposalCreated
Section titled “OnBarterProposalCreated”When: a barter proposal or a seller’s counteroffer has been sent (after CanCreateBarterProposal). The offered items and money are now held in escrow.
| Field | Meaning |
|---|---|
actorSource, actorId |
Who sent it |
recipientSource, recipientId |
Who receives it |
proposalType |
'proposal' or 'counter' |
offeredItems, wantedItems, offerAmount |
Contents |
deliveryMode |
Chosen delivery mode |
messageId, listingId |
IDs |
How to test: two players; B sends a proposal on A’s barter listing, then A counters it.
OnBarterProposalStatusChanged
Section titled “OnBarterProposalStatusChanged”When: a barter proposal changes state.
status |
Meaning |
|---|---|
'accepted' |
Accepted; the trade is created |
'countered' |
Answered with a counteroffer |
'rejected' |
Rejected; the offered items and money go back |
'cancelled' |
Withdrawn by its author |
'completed' |
The trade finished |
| Field | Meaning |
|---|---|
actorSource, actorId, actorName |
Who changed it |
proposalFromId, proposalToId |
Author and recipient |
status |
See above |
messageId, tradeId, listingId |
IDs |
How to test: follow a barter from proposal to acceptance, and another one to rejection.
Refunds
Section titled “Refunds”Refunds need Config.Refunds.Enabled = true. A buyer can request one within WindowDays (7) of the purchase.
OnRefundRequested
Section titled “OnRefundRequested”When: a buyer opens a refund request (after CanRequestRefund).
| Field | Meaning |
|---|---|
refundId, historyId |
Request and purchase |
buyerSource, buyerId, buyerName, sellerSource, sellerId, sellerName |
The players |
item, itemLabel, quantity |
What was bought |
amount |
Amount requested |
reason |
Buyer’s explanation |
listingId |
Listing ID |
OnRefundApproved
Section titled “OnRefundApproved”When: a refund is approved and the money returned to the buyer. Three ways: the seller approves it, an admin forces it (forced = true, and OnAdminAction also fires), or nobody answers within AutoApproveAfterHours (72 h; checked every hour).
| Field | Meaning |
|---|---|
refundId, historyId |
Request and purchase |
buyerSource, buyerId, buyerName, sellerSource, sellerId, sellerName |
The players |
item, itemLabel, quantity |
What was bought |
originalPrice |
Price paid |
amount / refundAmount |
Amount refunded |
forced |
true if an admin forced it |
resolvedBy, resolutionType, status, stage |
How it was resolved |
listingId |
Listing ID |
OnRefundRejected
Section titled “OnRefundRejected”When: the seller rejects a refund request.
| Field | Meaning |
|---|---|
refundId, historyId |
Request and purchase |
buyerSource, buyerId, buyerName, sellerSource, sellerId, sellerName |
The players |
amount |
Amount requested |
note |
The seller’s note |
resolvedBy |
Who rejected it |
listingId |
Listing ID |
How to test the three: two players. B buys from A and requests a refund (OnRefundRequested). A approves it (OnRefundApproved) or rejects it (OnRefundRejected). Force another one from /marketadmin to see forced = true.
Social
Section titled “Social”OnPlayerRated
Section titled “OnPlayerRated”When: a buyer rates a seller after a purchase.
| Field | Meaning |
|---|---|
raterSource, raterId, raterName |
Who rated |
sellerSource, sellerId, sellerName |
Who was rated |
stars |
1 to 5 |
comment |
Comment, may be an empty string |
historyId, listingId |
Purchase and listing |
stage |
'submitted' |
Example: reward reviews
Handlers.OnPlayerRated = function(data) if #data.comment >= 20 and data.raterSource then exports.ox_inventory:AddItem(data.raterSource, 'money', 50) endendHow to test: buy something from another player and rate them.
OnMessageSent
Section titled “OnMessageSent”When: a message is sent in a listing’s chat: normal text, price offers, barter proposals… The recipient’s client gets sl-marketplace:onMessageReceived.
| Field | Meaning |
|---|---|
senderSource, senderId, senderName |
Sender |
recipientSource, recipientId, recipientName |
Recipient |
messageId, listingId |
IDs |
messageKind |
Kind of message (text, offer, barter…) |
body |
Text |
offerAmount, offeredItems, deliveryMode |
For offers and proposals |
How to test: open another player’s listing and send them a message.
OnFavoriteChanged
Section titled “OnFavoriteChanged”When: a player adds or removes a listing from their favourites.
| Field | Meaning |
|---|---|
playerSource, playerId, playerName |
The player |
listingId |
Listing |
favorited |
true added, false removed |
OnFollowChanged
Section titled “OnFollowChanged”When: a player follows or unfollows a seller.
| Field | Meaning |
|---|---|
followerSource, followerId, followerName |
The player |
sellerSource, sellerId |
The seller |
following |
true follows, false stopped |
OnWishlistChanged
Section titled “OnWishlistChanged”When: a player adds or removes an entry from their wishlist (Config.Wishlist.Enabled).
| Field | Meaning |
|---|---|
playerSource, playerId, playerName |
The player |
action |
'added' or 'removed' |
wishlistId |
Entry ID |
item, maxPrice, notifyOnce |
What they are looking for |
OnReportCreated
Section titled “OnReportCreated”When: a player reports a listing (Config.Reports.Enabled). After AutoHideThreshold (5) open reports the listing is hidden until an admin reviews it.
| Field | Meaning |
|---|---|
reportId |
Report ID |
reporterSource, reporterId, reporterName |
Who reported |
sellerId, sellerName |
Reported seller |
item, itemLabel, listingId |
The listing |
reason |
One of Config.Reports.Reasons |
description |
Player’s text |
How to test the social hooks: from the marketplace, favourite a listing, follow a seller, add an item to your wishlist and report a listing; each action prints its hook.
Profile and mailbox
Section titled “Profile and mailbox”OnProfileCreated
Section titled “OnProfileCreated”When: a player creates their marketplace shop (the first time they open it).
| Field | Meaning |
|---|---|
playerSource, playerId, playerName |
The player |
shopName, bio, avatarColor |
Their profile |
lang |
Chosen language |
How to test: with a character that has never opened the marketplace, press F6 and create the shop. To repeat it, delete that player’s row from marketplace_users (only on a test server).
OnProfileUpdated
Section titled “OnProfileUpdated”When: a player changes their profile or storefront.
| Field | Meaning |
|---|---|
playerSource, playerId, playerName |
The player |
shopName |
Shop name |
changedFields |
Which fields changed |
profile |
The profile after the change |
How to test: edit your shop name or bio from your profile.
OnMailboxClaimed
Section titled “OnMailboxClaimed”When: a player collects something from their marketplace mailbox: an item (from an auction, a return, a pickup…) or money (from a sale, a refund…).
| Field | Meaning |
|---|---|
playerSource, playerId, playerName |
The player |
mailboxId |
Mailbox entry |
claimType |
'item' or 'money' |
amount |
Money collected |
item, itemLabel, itemMetadata, quantity |
Item collected |
meetupPoint |
Meetup point, if it had to be picked up there |
reason |
Why it was in the mailbox |
How to test: win a test auction (/markettest listing mailbox auction bread 100, bid and wait 5 minutes): the item always goes to your mailbox. Open the mailbox and collect it (claimType = 'item'). Selling something to another player leaves the money in your mailbox, which tests claimType = 'money'.
Administration
Section titled “Administration”OnAdminAction
Section titled “OnAdminAction”When: an admin does something from /marketadmin.
action |
Meaning | Extra fields |
|---|---|---|
'force_cancel' |
Cancelled a listing | listingId |
'ban_user' |
Banned a player from the marketplace | targetId |
'unban_user' |
Lifted a ban | targetId |
'resolve_report' |
Resolved a report | reportId |
'force_refund' |
Forced a refund | refundId, listingId |
| Field | Meaning |
|---|---|
adminSource, adminId, adminName |
The admin |
action |
See above |
targetId |
Affected player |
details |
Extra data (for a forced refund: amount and sellerId) |
Example: audit log to Discord
Handlers.OnAdminAction = function(data) PerformHttpRequest(GetConvar('my_admin_webhook', ''), function() end, 'POST', json.encode({ content = ('**%s** did `%s` on %s'):format(data.adminName, data.action, tostring(data.targetId or data.listingId)) }), { ['Content-Type'] = 'application/json' })endHow to test: give yourself admin (add_ace group.admin marketplace.admin allow), open /marketadmin and cancel a listing, ban and unban a test player, resolve a report and force a refund.
config.lua callbacks
Section titled “config.lua callbacks”Two older callbacks live in config.lua instead of handlers.lua. They still work and are called together with the hooks above.
Config.Notify
Section titled “Config.Notify”When: every time the marketplace shows a notification to a player from the server. Replace its body to use your own notification system.
Config.Notify = function(src, msg, type) TriggerClientEvent('ox_lib:notify', src, { description = msg, type = type or 'inform' })endHow to test: do anything that shows a notification (buy something, fail a purchase for lack of money) and check it appears with your system.
Config.OnDeliveryRobbed
Section titled “Config.OnDeliveryRobbed”When: exactly when OnDeliveryRobbed fires, just before it, once per delivery.
Config.OnDeliveryRobbed = function(thiefSrc, deliveryId, value, trigger) -- trigger: 'driver_killed' | 'cargo_stolen' TriggerEvent('dispatch:robbery', thiefSrc, GetEntityCoords(GetPlayerPed(thiefSrc)))endUse one of the two, not both, or you will send two alerts per robbery. Handlers.OnDeliveryRobbed is recommended: it receives more data and shows up in /markethandlers.