How Integrations Work#
Nothing inside Dealership Creator knows which framework, target or inventory you run. Every third-party resource is reached through a contract, and one small bridge file per backend fills that contract in. Detection happens at boot, and the console prints what it picked.
Layer | Supported | Without it |
|---|---|---|
Framework |
| Runs standalone: its own money handling and no car registration — enough to try it on an empty server. |
Vehicles | Your framework's own table — | Follows the framework. Set it by hand only when a standalone garage owns that table. |
Target |
| Counters and display cars fall back to a drawn marker and a keypress. |
Inventory |
| No item currencies. Everything else works. |
Vehicle keys |
| Bought and test-drive cars are handed over without a key. |
Banking |
| Payments still happen; no statement line is mirrored, and job tills are kept by the script. |
Phone |
| On-screen notifications only, no phone push. |
Screenshots |
| The photo studio is hidden; pictures stay manual. |
Notifications |
| ox_lib, which is a dependency anyway — and the fallback if the chosen one ever fails. |
HUD |
| The player's HUD stays on screen in showrooms and windows. |
Weather sync |
| Nothing to pause. With an unlisted sync running, the photo studio may flash while the two fight over the clock. |
Database |
| Required. The only one. |
Every optional integration degrades silently. A missing resource makes its feature stand down, not throw. That is why the boot summary matters — it is the only place that tells you an integration is absent before a player does.
Notifications and the HUD#
Notifications#
Config.Notify decides how the messages shown over the game look — "your car is delivered", "you are too far". Detection picks the first notification resource it finds running; the framework's own toasts ("qb", "qbx", "esx") are only used when you set them by hand. Set "interface" for the script's own toasts, styled like its windows.
-- config/shared/config.lua
Config.Notify = "okokNotify" -- or leave the line commented and let it detectIf the chosen system ever fails — stopped, or an export renamed in an update — the message is shown through ox_lib instead, so nothing is lost.
Hiding the player's HUD#
With a supported HUD running, it is hidden while a showroom, either window, a test drive, the creator, the furnishing tools or the photo tool is in use, and comes back the moment none is. Config.HideHud switches each of those moments on or off:
Config.HideHud = {
window = true,
showroom = true,
testDrive = true,
creator = true,
decorate = true,
capture = true, -- or the HUD ends up in every catalogue picture
}For a HUD or notification resource that is not listed, set the value to "custom" and fill in the one function in client/custom/hud/custom.lua or client/custom/notify/custom.lua.
Discord Logs#
Everything players do at your dealerships can be posted to Discord as an embed — 47 kinds of log, each with the player and their identifiers, the car and its picture, the plate, the amount and the dealership, in your server's language. Both tables live in config/server/webhooks.lua.
Channel | What goes there |
|---|---|
| Cars sold, bought back, financed, paid off, repossessed and hired. |
| Test drives, sales-desk deals and commissions, the till, staff, furniture and forecourt cars. |
| Restock runs: ordered, bought in directly, delivered, lost, out of time, failed. |
| Dealerships created, edited, deleted and handed over, teleports, the catalogue, the settings. |
| Refusals: a player not where they claimed, a tampered request, an admin action refused, a rate limit, a refund that needs fixing by hand. |
| Anything sent to a channel with no URL. Leave it empty too and that log is not sent. |
-- config/server/webhooks.lua
Config.Webhooks = {
default = '',
sales = 'https://discord.com/api/webhooks/...',
security = 'https://discord.com/api/webhooks/...',
}
Config.Logs = {
purchase = { channel = 'sales' }, -- the default
test_drive_started = { channel = 'https://discord.com/api/webhooks/...' }, -- a channel of its own
furniture_bought = { channel = 'activity', enabled = false }, -- never sent
}Config.LogOptions sets the webhook's name and avatar, which identifiers are shown under a player (discord becomes a clickable mention), whether the car's picture is attached, and whether owned shops may have a channel of their own. Run qs-dealership:testlogs in the server console to send a test to every channel and see which ones Discord accepted.
A channel per dealership#
An owner — or any rank with the settings right — pastes a webhook in their shop's Overview → Discord logs in the player's window, and that shop's sales, staff, till, test drives and restock runs are posted there as well as to your channels. An admin can set it on the creator's Trading tab. Only Discord webhook addresses are accepted, and once saved the address is never shown back to a player.
Overriding Detection#
Each layer is detected by looking for started resources in priority order — the first one found wins. An explicit value in config/shared/config.lua always beats detection, and the boot summary reports it as (manual) so you can see it was deliberate.
-- Auto, the default: the first started resource in the list wins.
Config.Inventory = ConfigAutoDetect('Inventory', {
'ox_inventory',
'qs-advanced-inventory',
'qs-inventory',
'qb-inventory',
}, 'vanilla')
-- Manual: skip detection entirely.
Config.Inventory = 'ox_inventory'This is worth doing when two candidates run at once, or when a resource has been renamed on your server and detection cannot see it under its usual name. Detection only sees resources that are already started, so anything you want found must be above ensure qs-dealership in server.cfg.
Garages, Tuning Shops and Restock Cars#
Restock-run vehicles and test-drive cars must not be stored, tuned or sold. Most garage and tuning scripts can be told to refuse them with one call, on the client:
if exports['qs-dealership']:IsTemporaryVehicle(vehicle) then
return -- a restock run or a test drive: not yours to store
endRestock vehicles also carry a replicated state-bag key that any script can read without calling anything. IsMissionVehicle answers for restock runs only, IsTestDriveVehicle for test drives only. See Commands and Exports.
A Custom Currency#
A VIP or donator coin that lives in your own table, or in another script, is wired in one file: server/custom/currency/custom.lua. It has three small functions — read a balance, take some, give some back — and two complete examples commented out: one for a column in your own users table, one for another resource's exports.
-- server/custom/currency/custom.lua
function Currency.Get(source, currencyId) ... end -- nil = cannot be read, 0 = has none
function Currency.Remove(source, currencyId, amount, reason) ... end
function Currency.Add(source, currencyId, amount, reason) ... endUncomment the example that matches, change the table or export name, and restart. Until that file is filled in, the currency does not appear anywhere — a currency the server cannot read is never offered at a balance of zero.
Implement
RemoveandAddtogether. A split payment takes from several currencies in turn, and if a later one fails the earlier ones are given back throughAdd. Without it, a refused purchase would quietly keep the player's coins.
Adding a Backend#
Supporting something that is not on the list is deliberately small: one file plus one line. Nothing else in the resource changes, because nothing else ever refers to your framework by name.
Copy the closest bridge
Every bridge is a small, unencrypted file under
client/custom/<kind>/orserver/custom/<kind>/. Copy the one nearest to yours —server/custom/inventory/ox_inventory.lua, say — and rename it after your resource.Change the calls inside
Each bridge is guarded so it only runs when it is the chosen backend, and fills a few functions with your resource's own exports:
lua if Config.Inventory ~= 'my_inventory' then return end function Inventory.GetItemCount(source, item) ... end function Inventory.RemoveItem(source, item, count) ... endRegister it for detection
Add one entry to the matching
ConfigAutoDetectlist inconfig/shared/config.lua, so it is found automatically and reported in the boot summary.
Frameworks, targets, keys, banking and phones extend exactly the same way, against their own contracts. If that is more than you want to take on, send us the name of the resource.
Languages#
Five complete translations ship in locales/: English (en), Spanish (es), French (fr), German (de) and Portuguese (pt). Set Config.Locale in config/shared/config.lua. To add another, copy en.json to the new code, translate it and set the locale to that code — anything left untranslated falls back to English.



