Installation

Step-by-step setup guide for oxide-blackmarket using ox_lib, oxmysql, and o-link.

Step-by-step setup for oxide-blackmarket.

Prerequisites

Required resources

ResourceRequiredPurpose
ox_libYesLocale, commands, utility helpers
oxmysqlYesDatabase access — stores this resource's settings in the shared oxide_settings table
o-linkYesFramework, job, money, inventory, notify, phone, banking, dispatch, callback, and targeting abstraction
oxide-policeNoOnly used if you turn on Config.ArrestPoliceIntegration, to pay the arrest reward into the officer's real department treasury

If ox_lib, oxmysql, and o-link are already running on your server, you don't need to install anything else (unless you want the optional oxide-police integration). Every framework already runs oxmysql, so this is almost certainly already installed.

Database

This resource stores its configuration in a database table called oxide_settings. You do not need to import any SQL — the table is created automatically the first time the resource starts. (A copy of the table definition ships in sql/install.sql for reference, or if you prefer to create it by hand.) How settings work is explained in the Configuration Reference; the short version is in step 5 below.

OneSync

OneSync must be enabled. The dealer NPCs are created by the server and synced to every player — without OneSync they will not appear. The resource prints a clear error at startup when OneSync is off.

server.cfg
set onesync on

Installation

Place the resource

Place oxide-blackmarket in your server's resources folder.

Add startup order

Start oxmysql, ox_lib, and o-link before this resource:

server.cfg
ensure oxmysql
ensure ox_lib
ensure o-link
ensure oxide-blackmarket

If your framework or inventory resources start oxmysql and o-link for you, just make sure oxide-blackmarket comes after them.

Add the pager item

The "Burner Pager" lets players ask around for the dealer's location. The resource handles what happens when the item is used — you only need to add the item itself to your inventory system so it exists.

An item image (blackmarket_pager.png) ships in the root of the resource folder. Copy it to your inventory's image folder as part of the steps below.

QBCore — add the item to qb-core/shared/items.lua, then copy blackmarket_pager.png to qb-inventory/html/images/:

blackmarket_pager = { name = 'blackmarket_pager', label = 'Burner Pager', weight = 100, type = 'item', image = 'blackmarket_pager.png', unique = true, useable = true, shouldClose = true, description = 'A disposable pager for underground contacts' },

QBX / ESX (ox_inventory) — add the item to ox_inventory/data/items.lua, then copy blackmarket_pager.png to ox_inventory/web/images/:

['blackmarket_pager'] = {
    label = 'Burner Pager',
    weight = 100,
    stack = false,
    close = true,
    description = 'A disposable pager for underground contacts',
},

On QBX, do not add the item to qbx_core/shared/items.lua — that file is deprecated. ox_inventory's items file is the right place.

Set up dirty money

The shop pays players in "dirty money" when they sell, and takes it when they buy. Open shared/config.lua and set Config.DirtyMoney to match your framework.

ESX — use the built-in black_money account:

Config.DirtyMoney = {
    mode = 'account',
    account = 'black_money',
}

QBX — ox_inventory ships a black_money item, so use item mode (each item in the stack is worth $1):

Config.DirtyMoney = {
    mode = 'item',
    item = 'black_money',
}

QBCore — QBCore does not ship a stackable dirty money item out of the box, so either add one to qb-core/shared/items.lua and use item mode like the QBX example, or use marked bills that store their dollar value in metadata:

Config.DirtyMoney = {
    mode = 'item',
    item = 'markedbills',
    useMetadata = true,
    metadataKey = 'worth', -- match the field your bills actually use
}

Stock QBCore's markedbills item does not carry a worth value by itself — metadata mode only works if another script on your server creates bills with one. Check an existing bill in a player's inventory to see the exact field name before setting metadataKey.

Simplest option (any framework) — regular cash works everywhere:

Config.DirtyMoney = {
    mode = 'account',
    account = 'cash',
}

Review configuration

Do this before the first start. On its first start the resource copies everything in these files into the oxide_settings database table, and from then on it reads settings from the database — editing the .lua files afterward has no effect. This also means the dirty money setup in the previous step must be done before the first start. To change a setting later, see How Configuration Is Stored.

Check these files before going live:

  • shared/config.lua — dealer behavior, economy, police, loot, hit squad, spawn locations
  • shared/items.lua — what the dealers buy and sell, with prices

Settings worth checking first:

  • Config.Debug — turn on (true) while setting up to see helpful console output; leave off on a live server
  • Config.EnableTiers — whether players need reputation to unlock better stock
  • Config.DealerCount — how many dealers roam at once (default 3; capped at the number of Config.Locations)
  • Config.PoliceJobs — the job names on your server that count as police
  • Config.Locations — where dealers can spawn (you need at least as many as Config.DealerCount)
  • Config.ArrestDropOffs — where officers deliver arrested dealers (add points near your police stations)
  • Config.ArrestPoliceIntegration — turn on only if you run oxide-police and want the reward paid into department treasuries

The item names in shared/items.lua must match items that actually exist in your inventory system. The defaults reference items from other Oxide resources (weed, meth, weapon printing) — remove or replace any your server doesn't have.

See the Configuration Reference for the full option list.

Verification

Start the server and confirm ox_lib, o-link, and oxide-blackmarket load without dependency errors.

Set Config.Debug = true for the first run and watch server console output for:

[oxide-blackmarket] Settings loaded from DB (N keys)
[oxide-blackmarket] Pager item registered
[oxide-blackmarket] Resource starting...
[oxide-blackmarket] Initializing dealers...
[oxide-blackmarket] Spawned dealer 1 at location 3 (entity: ..., netId: ...)
[oxide-blackmarket] Dealer initialization complete (3/3)

The Settings loaded from DB line confirms the settings table was created and read. On the very first start it also imports your config files into the table. If any configured item names aren't recognized by your inventory, a warning lists them here — fix those typos in shared/items.lua.

Join as an admin and run /blackmarket status — you should get a "3 dealer(s) currently active" notification. Run /blackmarket goto to teleport straight to the nearest one.
Walk up to a dealer and confirm the "Trade" interaction opens the shop. Try the category tabs and the search box.
Buy and sell at least one item to verify inventory and dirty-money configuration.
If using police gameplay, switch to a job in Config.PoliceJobs, aim a weapon at a dealer (he should surrender), cuff him with "Detain Dealer", drive him to the nearest Config.ArrestDropOffs point, and press [E] to hand him over.
If using pager intel, give yourself reputation with /blackmarket setrep [your id] 1000 and use the pager item — you should get the nearest dealer's location.

Optional Setup

Pager phone messages

When a Tier 2+ player successfully uses the pager, the resource sends an anonymous tip email through your phone system (via o-link), with the detail level scaling by tier. If your phone isn't set up for this, nothing breaks — the player still gets a notification, and Tier 4 still drops a map waypoint.

Police department deposits

When an officer delivers an arrested dealer to a drop-off, who gets paid is set by Config.ArrestRewardRecipient ('officer', 'society', or 'both'). The society deposit goes to the police account through your banking system (via o-link). If your banking setup doesn't support this, the arrest still works and the officer still gets his personal cash — only the department deposit is skipped (with a warning in the server log).

oxide-police department treasury

If you run oxide-police and set Config.ArrestPoliceIntegration = true, the department cut is paid straight into the arresting officer's real oxide-police department treasury on delivery, instead of the generic society deposit. The officer still gets his personal cash portion. This does not create an NPC arrest or custody record. If oxide-police isn't installed, the resource quietly falls back to the standalone society deposit — so it's safe to leave this off.

Arrest drop-off points

Officers deliver cuffed dealers to the nearest point in Config.ArrestDropOffs. The defaults sit at Mission Row, Davis, Paleto, and Sandy Shores. Add points near your own police stations so an officer always has a drop-off within reach.

Dealer locations

Each dealer picks its own random spot from Config.Locations (no two share one):

Config.Locations = {
    vector4(x, y, z, heading),
}

You need at least as many locations as Config.DealerCount.

Use open outdoor areas. Dealers wander around their spawn points, and indoor or cramped spots tend to break pathing.

Next Steps