Skip to Content
GuidesCreate a QBCore Side Job Resource

Create a QBCore side job

This guide builds a delivery job without editing an existing gameplay resource. The client handles prompts and route state; the server validates job state and pays the player.

Define the job

Add the definition to qb-core/shared/jobs.lua and restart qb-core on a test server:

QBShared.Jobs.delivery = { label = 'Delivery', defaultDuty = true, offDutyPay = false, grades = { ['0'] = { name = 'Rookie', payment = 200 } } }

Create the resource

Create resources/[local]/delivery-job/fxmanifest.lua:

fx_version 'cerulean' game 'gta5' lua54 'yes' client_script 'client.lua' server_script 'server.lua' dependency 'qb-core'

Add ensure delivery-job after qb-core in server.cfg.

Keep assignment and payouts on the server

Do not expose an event that lets any client choose a job or payout. Assign the job through an authorized admin/cityhall workflow. For the route, store issued work server-side and ignore any client-supplied amount:

local QBCore = exports['qb-core']:GetCoreObject() local activeRoutes = {} RegisterNetEvent('delivery:server:startRoute', function() local src = source local Player = QBCore.Functions.GetPlayer(src) if not Player or Player.PlayerData.job.name ~= 'delivery' then return end if activeRoutes[src] then return end activeRoutes[src] = { stopsRemaining = 3 } TriggerClientEvent('delivery:client:routeStarted', src, 3) end) RegisterNetEvent('delivery:server:completeStop', function() local src = source local Player = QBCore.Functions.GetPlayer(src) local route = activeRoutes[src] if not Player or Player.PlayerData.job.name ~= 'delivery' or not route then return end route.stopsRemaining = route.stopsRemaining - 1 if route.stopsRemaining > 0 then return end activeRoutes[src] = nil Player.Functions.AddMoney('bank', 200, 'delivery-route') end) AddEventHandler('playerDropped', function() activeRoutes[source] = nil end)

For production, also validate proximity, route order, cooldown, and entity ownership on the server.

Add the client interaction

Use qb-target, qb-menu, or a marker to request a route. The client should send an intent such as “start route” or “complete stop”, never a payout.

Test the resource

Restart qb-core and the new resource on a test server. Assign grade 0, reconnect, start and finish one route, reject an invalid payout request, and confirm the resource stops without leaving targets or entities behind.