API Reference
Server callbacks, pricing behavior, and integration expectations for Oxide Drugselling.
Technical reference for the current oxide-drugselling integration points.
Public Resource Exports
oxide-drugselling does not currently register public FiveM exports of its own.
This document covers:
- the sale hook (event + config function) fired on every completed sale
- the internal pricing helper used by the resource
- the server callbacks used between client and server
- the external exports expected from optional source drug resources
- the NUI actions used by the packaged frontend
Sale Hook
Both fire on the server once per completed sale, covering all acceptance paths (instant accept, negotiated accept, and accepted counter-offer). Use either or both. They run after the item is removed and the player is paid.
Each receives the same saleData table:
| Field | Type | Description |
|---|---|---|
source | number | Seller's server id |
charId | string | Seller's character identifier |
drugType | string | Config.Drugs key (e.g. weed) |
itemName | string | Item that was sold |
quantity | number | Units sold |
finalPrice | number | Total amount paid |
metaKey | string | Metadata group key for the sold stack |
mode | string | Config.DirtyMoney.mode used for payout |
Event: oxide-drugselling:drugSold
A plain server-side event (not net), so clients cannot trigger it. Use this when you prefer a listener in your own resource.
AddEventHandler('oxide-drugselling:drugSold', function(src, saleData)
-- saleData.finalPrice, saleData.drugType, ...
end)Config function: Config.OnDrugSold
A function in shared/config.lua (escrow-ignored, so editable) that runs on each sale. It is wrapped in pcall, so an error in your code is logged and the sale still completes. Leave the body empty to do nothing.
Config.OnDrugSold = function(saleData)
local turfId = exports['op-crime']:getPlayerTurfZone(saleData.source)
if turfId then
TriggerEvent('op-crime:drugSold', saleData.source, turfId, saleData.finalPrice)
end
endInternal Pricing Helper
PricingPipeline.Calculate
Calculates fair price per unit and bonus-detail data for an item group.
local fairPricePerUnit, bonusDetails = PricingPipeline.Calculate(drugCfg, itemCfg, metadata)| Parameter | Type | Description |
|---|---|---|
drugCfg | table | Entry from Config.Drugs[drugKey] |
itemCfg | table | Item definition with label and basePrice |
metadata | table or nil | Item metadata used by modifier resolution |
Returns:
| Value | Type | Description |
|---|---|---|
fairPricePerUnit | number | Floored fair value per unit |
bonusDetails | table | UI-facing bonus/tag data |
Server Callbacks
These callbacks are registered through Callback = olink.callback.
oxide-drugselling:server:getSellableItems
Returns sellable inventory entries grouped by item and metadata.
local items = Callback.Trigger('oxide-drugselling:server:getSellableItems')Current behavior:
- enforces the configured police minimum
- reads player inventory through
o-link.inventory - applies progression-level checks per drug type
- calculates fair price per group before the panel opens
Rate limit: 3000 ms
Response shape:
{
{
drugType = 'weed',
itemName = 'weed_1g',
label = 'Weed (1g)',
basePrice = 25,
groups = {
{
metaKey = 'strain123:Gas',
label = 'OG Kush',
grade = 'Gas',
gradeColor = 'text-purple-400',
score = 91,
bonuses = { ... },
available = 3,
fairPricePerUnit = 52,
},
},
},
}oxide-drugselling:server:initSale
Validates the selected group, calculates the fair total price, rolls risk outcomes, and either processes the sale or returns a negotiation result.
local result = Callback.Trigger('oxide-drugselling:server:initSale', {
drugType = 'weed',
itemName = 'weed_1g',
quantity = 5,
metaKey = 'strain123:Gas',
playerPrice = 200,
npcModel = 1234567890,
})Rate limit: 5000 ms
Possible result values:
acceptcounterrejectrobberyerror
Possible return fields:
| Field | Meaning |
|---|---|
result | Outcome type |
finalPrice | Paid amount on acceptance |
counterPrice | Offer returned by the NPC |
itemsLost | Quantity stolen during robbery |
cashLost | Dirty-money amount stolen during robbery |
message | Error reason such as missing_items |
policeDispatched | Whether the dispatch roll succeeded |
oxide-drugselling:server:acceptCounter
Accepts the player's currently pending counter-offer.
local result = Callback.Trigger('oxide-drugselling:server:acceptCounter')Rate limit: 5000 ms
Notes:
- pending counters expire after
60seconds - accepted counters process item removal, payout, and progression just like a direct acceptance
Optional Source-Resource Exports
oxide-drugselling can call these exports on source drug resources when a drug type defines a progression block or a trait_bonus modifier.
GetPlayerLevel
Expected signature:
exports('GetPlayerLevel', function(source)
return playerLevel
end)Used for:
- per-drug selling level requirements
AddXP
Expected signature:
exports('AddXP', function(source, amount)
end)Used for:
- awarding
(xpPerUnit * quantity)after a successful sale
AddSold
Expected signature:
exports('AddSold', function(source, quantity)
end)Used for:
- tracking sold units after a successful sale
GetStrainData
Expected signature for the shipped weed config:
exports('GetStrainData', function(strainId)
return {
traits = {
thc = 85,
potency = 72,
},
}
end)Used for:
- resolving
trait_bonusdata from weed strain metadata
If a source resource is not started, the call is skipped and selling continues.
NUI Actions
Lua to NUI
| Action | Payload | Purpose |
|---|---|---|
openSellPanel | { items, isGangNpc, panelTitle } | Opens the sell panel |
sellThinking | none | Switches to the pending state |
sellResult | { result, finalPrice?, counterPrice?, itemsLost?, cashLost?, policeDispatched? } | Displays the final outcome |
close | none | Closes the panel |
NUI to Lua
| Callback | Payload | Purpose |
|---|---|---|
sellConfirm | { drugType, itemName, quantity, metaKey, playerPrice, isGangNpc } | Submit a player offer |
sellAcceptCounter | none | Accept a counter-offer |
sellClose | none | Close the sale |
close | none | Generic close action |
getLocale | none | Returns { locale } from the ox:locale convar for the frontend locale loader |
Integration Notes
If you are adding a custom drug-production resource and want it to work with oxide-drugselling:
- register your item names in the inventory used by
o-link - attach metadata fields that match your
Config.Drugsdefinitions - add optional progression exports if you want level gating and XP/sold tracking
- add the new drug entry in
shared/config/drugs.lua