Standalone
Agency-Vehicleshop
A premium vehicle dealership for FiveM. Browse a fully animated showroom, take test drives and buy cars through a sleek glassmorphism NUI. Salesperson job with commissions, category & price filters, live in-world preview, test-drive timer, financing, dealer management dashboard and Discord webhook logging. 13 languages, MySQL persistence & ACE permissions. Works with QBCore, ESX & Standalone.

01 Configuration
Complete config.lua for Agency-Vehicleshop. All options documented via inline comments.
--[[
╔══════════════════════════════════════════════════════════════════╗
║ AGENCY VEHICLE SHOP ║
║ Premium Buy & Sell Car Dealership ║
║ (c) Agency Scripts ║
╠══════════════════════════════════════════════════════════════════╣
║ Plug & Play · QBCore / ESX / Standalone · Multi-Phone ready ║
╚══════════════════════════════════════════════════════════════════╝
This file is the ONLY thing you need to touch as a server owner.
Everything is commented. No coding knowledge required.
Framework options (Config.Framework):
'auto' -> Auto-detect QBCore or ESX (recommended)
'qb' -> Force QBCore
'esx' -> Force ESX
'standalone' -> No framework. Vehicles are managed by this script.
]]
Config = {}
-- =====================================================================
-- AGENCY SCRIPTS INTEGRATION ⭐
-- =====================================================================
-- Official integration with other Agency Scripts.
-- true = Always use (throws error if script is missing)
-- false = Never use (even if installed)
-- 'auto' = Auto-detect if the script is running on the server (recommended)
--
Config.AgencyNotify = 'auto' -- Agency-Notify → Premium notifications
Config.AgencyGarage = 'auto' -- Agency-Garage → Bought vehicles appear directly in the garage
Config.AgencyVehiclekeys = 'auto' -- Agency-Vehiclekeys → Receive keys automatically after purchase
-- =====================================================================
-- FRAMEWORK & AUTO-DETECTION
-- =====================================================================
Config.Framework = 'auto' -- 'auto' | 'qb' | 'esx' | 'standalone'
Config.QBCoreResource = 'qb-core'
Config.ESXResource = 'es_extended'
Config.Debug = true -- TEMP: set to false after debugging
Config.AutoSetupDatabase = true -- creates standalone table / ESX columns on start
-- =====================================================================
-- LANGUAGE
-- =====================================================================
Config.Locale = 'en' -- 'en','de','fr','es','pt','it','nl','da','sv','no','fi','pl','cs','sk','hu','ro','bg','tr','ru','el','ar','zh','ja','ko' (texts live in locales.lua)
-- =====================================================================
-- BRIDGES (auto-detected — only force if needed)
-- =====================================================================
-- These settings are ONLY used if the Agency integrations above
-- are NOT active. With 'auto', Agency is checked first, then these.
Config.Notify = 'auto' -- 'auto' | 'ox' | 'qb' | 'esx' | 'native'
Config.TextUI = 'auto' -- 'auto' | 'ox' | 'jg' | 'qb' | 'native'
Config.VehicleKeys = 'auto' -- 'auto' | 'qb' | 'qs' | 'wasabi' | 'mk' | 'none'
-- =====================================================================
-- MULTI-PHONE INTEGRATION ⭐
-- =====================================================================
-- A bought vehicle is inserted into the standard table (player_vehicles for
-- QB, owned_vehicles for ESX) with state = 1 (stored). Every phone garage app
-- and any garage script then sees the new car automatically.
Config.PhoneSync = true
Config.PhoneSyncEvent = 'vehicleshop:vehiclePurchased'
-- =====================================================================
-- VEHICLE CATALOG ⭐ (where the buyable cars come from)
-- =====================================================================
-- 'auto' -> use qb-core/shared/vehicles.lua if it exists, else the Config.Vehicles list
-- 'qbcore' -> always read qb-core/shared/vehicles.lua (model/name/brand/price/category/shop)
-- 'config' -> always use the Config.Vehicles list below (best for ESX / standalone)
-- On QBCore you do NOT have to list any vehicles — they are all loaded for you.
Config.VehicleSource = 'auto'
-- Manual catalog (used when source = 'config' or as a fallback). Add your own here.
-- shop = which shop it shows up in (matches a Config.Shops 'type')
Config.Vehicles = {
{ model = 'sultan', name = 'Sultan', brand = 'Karin', price = 12000, category = 'sports', shop = 'pdm' },
{ model = 'kuruma', name = 'Kuruma', brand = 'Karin', price = 95000, category = 'sports', shop = 'pdm' },
{ model = 'futo', name = 'Futo', brand = 'Karin', price = 9000, category = 'sports', shop = 'pdm' },
{ model = 'adder', name = 'Adder', brand = 'Truffade', price = 1000000, category = 'super', shop = 'luxury' },
{ model = 'zentorno', name = 'Zentorno', brand = 'Pegassi', price = 725000, category = 'super', shop = 'luxury' },
{ model = 'bati', name = 'Bati 801', brand = 'Pegassi', price = 15000, category = 'motorcycles', shop = 'moto' },
}
-- =====================================================================
-- BUYING & SELLING
-- =====================================================================
-- Payment methods the player can choose from IN the shop menu.
-- 'bank' = card, 'cash' = cash. Both enabled = player picks in the UI.
Config.PaymentMethods = { 'bank', 'cash' } -- available: 'bank', 'cash'
Config.DefaultPayment = 'bank' -- pre-selected method when the shop opens
-- AgencyPay (phone wallet) checkout. The purchase is verified SERVER-SIDE via
-- agency-phone's VerifyAgencyPayCharge export, so a forged result cannot grant a
-- free vehicle. Requires agency-phone to be running.
Config.EnableAgencyPay = true
Config.Sell = {
enabled = true,
account = 'bank', -- where the money goes when selling
returnPercent = 50, -- % of the catalog price you get back when selling
}
-- =====================================================================
-- DEALERSHIP OWNERSHIP ⭐ (players can buy & own shops as a business)
-- =====================================================================
Config.Ownership = {
enabled = true, -- master switch for the ownership system
maxPerPlayer = 2, -- max dealerships one player can own
sellBackPercent = 50, -- % of purchasePrice you get back when selling the business
defaultCommission = 0.10, -- 10% of each vehicle sale goes into the business account
maxEmployees = 10, -- max employees per dealership
ranks = {
{ name = 'owner', label = 'Owner', canHire = true, canFire = true, canWithdraw = true },
{ name = 'manager', label = 'Manager', canHire = true, canFire = true, canWithdraw = false },
{ name = 'employee', label = 'Employee', canHire = false, canFire = false, canWithdraw = false },
},
-- ===== STOCK & SUPPLY (only applies to OWNED dealerships) =====
-- An UNOWNED dealership sells everything at the normal price with infinite
-- stock. The moment a player buys it the showroom starts EMPTY — the owner
-- has to order vehicles wholesale (an up-front investment), drive a delivery
-- run for each one, and only then can sell them to customers at the normal
-- (higher) price. The margin lands in the business account.
stock = {
enabled = true,
maxOrderAtOnce = 5, -- max units that can be ordered in one order (your "max 5")
wholesaleFactor = 0.55, -- order price = 55% of catalog price → ~45% margin on resale
maxPerModel = 10, -- max delivered units a dealership can hold per model
requireDelivery = true, -- ordered units must be delivered before they can be sold
},
}
-- =====================================================================
-- DELIVERY MISSIONS ⭐ (owners drive ordered vehicles to the dealership)
-- =====================================================================
-- After ordering stock, ONE delivery run is required per ordered unit. The
-- driver picks the vehicle up at one of the warehouse points below and drives
-- it to the dealership's spawn point. The game alternates pickup points so the
-- route differs each time. Fully configurable — add/remove points freely.
Config.Delivery = {
payOnComplete = 0, -- optional extra cash per delivery (profit normally comes from sales)
pickupMarker = { type = 1, size = 3.0, color = { 0, 212, 255, 140 } },
dropMarker = { type = 1, size = 3.0, color = { 0, 255, 136, 140 } },
-- Transporter vehicles used when ordering multiple vehicles at once
truckSmall = 'speedo', -- Changed from 'mule' because mule is often blacklisted
truckLarge = 'benson', -- Changed from 'pounder' because pounder is often blacklisted
pickups = {
vector4(1730.03, 3307.72, 41.22, 195.0), -- Sandy Shores Airfield (Runway)
vector4(-192.51, 6224.71, 31.49, 134.42), -- Paleto Bay (Open rest stop parking)
vector4(-2184.28, 4272.78, 49.03, 130.0), -- Highway 1 parking (near Zancudo)
vector4(-341.36, -2600.32, 6.0, 275.0), -- Elysian Island (Open container lot)
vector4(-1058.46, -2824.93, 27.7, 325.0), -- LSIA (Outer gate open parking)
vector4(2112.35, 1925.15, 78.4, 130.0), -- Wind Farm (Open dirt track)
vector4(-3173.34, 1079.22, 20.83, 240.0), -- Chumash (Open dirt lot next to highway)
vector4(-392.21, 1177.3, 325.64, 340.0), -- Galileo Observatory (Empty parking lot)
vector4(695.53, 580.4, 130.4, 270.0), -- Vinewood Bowl (Large parking area)
vector4(-1203.25, -1355.22, 4.3, 120.0), -- Vespucci Beach (Giant open parking lot)
vector4(-1678.5, -960.5, 7.6, 135.0), -- Del Perro Pier (Parking lot)
vector4(890.3, -2200.5, 30.5, 180.0), -- Cypress Flats (Industrial open road)
vector4(1420.4, -1890.6, 73.0, 290.0), -- El Burro Heights (Oil fields dirt track)
vector4(1950.4, 3770.6, 32.2, 210.0), -- Harmony / Route 68 (Dirt parking)
vector4(-735.6, 5835.4, 17.3, 225.0), -- Mount Chiliad (Cable car parking at bottom)
vector4(2450.4, 4950.6, 41.5, 45.0), -- Grapeseed (Farms dirt road)
vector4(-545.5, 5320.5, 74.5, 340.0), -- Paleto Forest (Lumber yard open space)
},
}
-- =====================================================================
-- SHOWCARS ⭐ (/avehicle — staff place display vehicles on fixed spots)
-- =====================================================================
-- Anyone with the internal job at a dealership can drive a car onto one of its
-- showcar spots and run /avehicle to display it (frozen showroom piece). Run
-- /avehicle clear on a spot to empty it. Customers just look — no buy here.
Config.Showcars = {
enabled = true,
command = 'avehicle', -- chat command for staff
freeze = true, -- display vehicles are frozen & invincible
setRange = 4.0, -- how close a spot must be to set/clear it
-- Display spots per shop id. Add as many vector4(x,y,z,heading) as you like.
spots = {
pdm = {
vector4(-43.92, -1097.62, 26.42, 25.0),
vector4(-47.83, -1100.30, 26.42, 25.0),
vector4(-51.74, -1102.98, 26.42, 25.0),
},
luxury = {
vector4(133.2, -138.5, 54.85, 250.0),
vector4(129.6, -141.0, 54.85, 250.0),
},
moto = {
vector4(-1250.6, -351.2, 36.91, 120.0),
},
planes = {},
boats = {},
},
}
Config.TestDrive = {
enabled = true,
duration = 45, -- seconds, then the test car despawns and you return
stopKey = 73, -- [X] key to end the test drive early
routingBucket = true, -- true = puts player in a private world during test drive
hudPosition = 'bottom-center', -- 'top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', 'bottom-right'
spawn = vector4(-1732.17, -2900.2, 13.94, 330.0), -- Default okok Test Track (Airport)
}
-- =====================================================================
-- GENERAL BEHAVIOUR
-- =====================================================================
Config.InteractKey = 38 -- [E]
Config.UseTarget = false -- true = ox_target / qb-target instead of marker+key
Config.DrawDistance = 25.0
Config.InteractDistance = 2.5
Config.SpawnInVehicle = true -- sit in the car after buying
Config.WarpDelay = 250
-- MARKER (animated icon at the shop)
Config.Marker = {
type = 36,
size = 0.55,
color = { 255, 215, 0, 200 }, -- yellow
bob = false, rotate = true, pulse = false, zOffset = 0.0,
}
-- SELL MARKER (where you sell your car)
Config.SellMarker = {
type = 36, -- 36 = Car icon marker
size = 0.6,
color = { 255, 50, 50, 200 }, -- vibrant red
bob = false, rotate = true, pulse = false, zOffset = 0.0,
}
-- BOSS MARKER (management menu access)
Config.BossMarker = {
type = 36, -- 36 = car icon on the ground (like the shop marker)
size = 0.55,
color = { 0, 212, 255, 200 }, -- cyan = management (only staff see it)
bob = false, rotate = true, pulse = true, zOffset = 0.0,
}
-- OPEN HINT
Config.OpenHint = { mode = 'notify' } -- 'notify' | 'textui' | 'both'
-- =====================================================================
-- VEHICLE PREVIEW (3D showroom camera, mouse-drag to rotate)
-- =====================================================================
Config.Preview = {
enabled = true,
autoRotate = false, -- false = drag with the mouse · true = spins by itself
mouseSensitivity = 0.35,
rotateSpeed = 18.0,
heightOffset = 25.0, -- fallback only
hotspots = true, -- show interactive dots (doors, hood, trunk) on the preview car
}
-- =====================================================================
-- VEHICLE IMAGES FOR THE UI
-- =====================================================================
-- 'spawn' -> html/img/vehicles/<model>.png (e.g. adder.png)
-- 'class' -> one image per category
-- 'single' -> always default.png
-- Missing image -> clean placeholder icon (never a broken image).
Config.VehicleImages = 'spawn'
-- =====================================================================
-- BLIPS
-- =====================================================================
Config.Blips = { enabled = true }
-- =====================================================================
-- CATEGORY DISPLAY NAMES (GTA vehicle classes)
-- =====================================================================
Config.CategoryLabels = {
compacts = 'Compacts', sedans = 'Sedans', suvs = 'SUVs', coupes = 'Coupes',
muscle = 'Muscle', sportsclassics = 'Classics', sports = 'Sports', super = 'Super',
motorcycles = 'Motorcycles', offroad = 'Off-Road', industrial = 'Industrial',
utility = 'Utility', vans = 'Vans', cycles = 'Cycles', boats = 'Boats',
helicopters = 'Helicopters', planes = 'Planes', service = 'Service',
emergency = 'Emergency', military = 'Military', commercial = 'Commercial',
}
-- =====================================================================
-- SHOPS (positions imported from the old shop)
-- =====================================================================
-- type: matches the 'shop' field of the vehicles (which cars are shown)
-- access: vector3 marker to open the shop
-- spawn: vector4 where the preview / bought car appears
-- sell: vector3 sell point (drive your car here, press [E] to sell)
Config.Shops = {
['pdm'] = {
label = 'Premium Deluxe Motorsport',
type = 'pdm',
access = vector3(-57.5, -1096.73, 26.42),
spawn = vector4(-47.4, -1093.4, 26.42, 150.0),
spawns = {
vector4(-47.4, -1093.4, 26.42, 150.0),
vector4(-50.8, -1089.2, 26.42, 150.0),
},
sell = vector3(-45.3, -1082.91, 26.27),
blip = { sprite = 225, color = 3, scale = 0.9 },
-- Ownership
ownable = true,
purchasePrice = 1000000,
bossMenu = vector3(-55.0, -1098.0, 26.42),
deliveryDrop = vector4(-31.84, -1090.72, 26.42, 340.0), -- Default drop for PDM
},
['moto'] = {
label = 'Motorcycle Shop',
type = 'moto',
access = vector3(-1253.95, -349.37, 36.91),
spawn = vector4(-1245.0, -353.0, 36.9, 30.0),
spawns = {
vector4(-1245.0, -353.0, 36.9, 30.0),
vector4(-1242.0, -351.0, 36.9, 30.0),
vector4(-1238.0, -348.0, 36.9, 30.0),
},
sell = vector3(-1242.49, -345.42, 37.33),
blip = { sprite = 226, color = 3, scale = 0.8 },
-- Ownership
ownable = true,
purchasePrice = 500000,
bossMenu = vector3(-1250.0, -349.0, 36.91),
deliveryDrop = vector4(-1256.6403, -335.6497, 36.9134, 299.5139),
},
['planes'] = {
label = 'Airplane Shop',
type = 'planes',
access = vector3(-949.5, -2946.55, 13.95),
spawn = vector4(-975.0, -2965.0, 13.95, 60.0),
spawns = {
vector4(-975.0, -2965.0, 13.95, 60.0),
},
sell = vector3(-959.5, -2946.55, 12.76),
blip = { sprite = 359, color = 3, scale = 0.8 },
-- Ownership
ownable = true,
purchasePrice = 3000000,
bossMenu = vector3(-955.0, -2943.0, 13.95),
deliveryDrop = vector4(-975.0, -2965.0, 13.95, 60.0),
},
['boats'] = {
label = 'Boat Shop',
type = 'boats',
access = vector3(-720.77, -1324.92, 1.6),
spawn = vector4(-735.0, -1338.0, 0.2, 140.0),
spawns = {
vector4(-735.0, -1338.0, 0.2, 140.0),
},
sell = vector3(-721.56, -1306.7, 3.82),
blip = { sprite = 427, color = 3, scale = 0.8 },
-- Ownership
ownable = true,
purchasePrice = 1500000,
bossMenu = vector3(-724.0, -1322.0, 1.6),
deliveryDrop = vector4(-735.0, -1338.0, 0.2, 140.0),
},
}
-- =====================================================================
-- BRANDING (subtle — paid script)
-- =====================================================================
Config.Branding = { showFooter = true, label = 'Agency Vehicle Shop' }
-- =====================================================================
-- TEXT / TRANSLATIONS
-- =====================================================================
-- =====================================================================
-- TEXT / TRANSLATIONS
-- =====================================================================
-- All translatable strings live in locales.lua (24 languages) and are
-- loaded right after this file (see fxmanifest.lua). Edit texts there.