gta6/prompts
economy
Freebeginnereconomy

Paycheck — Timed Payout by Job Grade

ESX timed paycheck that pays every online player a salary based on their job and grade on a fixed server interval.

NON-TESTÉ — the reference Lua is syntax-validated, not run in a live FiveM server. Adapt and test on your own dev server before shipping.
Est. Lua
~49 loc
Claude
Claude Opus 4.x / Sonnet 4.x
Validation
syntax-validated
Updated
2026-06-24

Description

An ESX paycheck system: every N minutes the server pays each online player a salary derived from their job and grade, deposits it into their bank account, and pings them with a notification. This is the passive income heartbeat of a roleplay economy and pairs directly with the salary-tiers and tax scripts.

Prompt Template

You are writing a FiveM resource for es_extended. The payout MUST run server-side only.

Framework: ESX. local ESX = exports['es_extended']:getSharedObject()

Server:
- Constant PAY_INTERVAL = 10 * 60 * 1000 (ten real minutes, in ms).
- A fallback PayTable keyed by job name then grade number, e.g.
  police = { [0]=250, [1]=350, ... }, plus unemployed = { [0]=50 }.
- A resolveSalary(job, grade) helper that prefers job.grade_salary when > 0,
  then PayTable[job.name][job.grade], then 0.
- A CreateThread { while true do Wait(PAY_INTERVAL); for _, xPlayer in
  pairs(ESX.GetExtendedPlayers()) do ... end end }. For each player resolve the
  salary; if > 0 call addAccountMoney("bank", salary) and TriggerClientEvent
  ("paycheck:received", xPlayer.source, salary, job.label).

Client:
- A "paycheck:received" net event that ShowNotification the amount and job label.

Hard requirements:
- Loop iterates ESX.GetExtendedPlayers() (xPlayer objects), NOT GetPlayers().
- Wait FIRST inside the loop so you do not pay everyone the instant the resource
  starts.
- Always have a fallback salary path so a missing grade does not silently pay 0.
- Deposit to bank, not cash, so paychecks are not lost on death/robbery.

Expected Output

The reference Lua at content/expected-outputs/economy/02-paycheck-by-job-grade.lua is a server-driven interval loop that resolves each player's salary (framework grade salary first, then a fallback table) and deposits to bank, with a tiny client notifier. The split: the loop is server_script 'server.lua'; the notification handler is client_script 'client.lua'.

02-paycheck-by-job-grade.lua50 lines
-- Resource: paycheck-system  (ESX)
-- Timed payout to every on-duty player, amount keyed by job + grade.
-- Server-only loop; client only shows a notification.

-- ===== server.lua =====
local ESX = exports['es_extended']:getSharedObject()

local PAY_INTERVAL = 10 * 60 * 1000 -- 10 real minutes

-- Fallback table when the grade has no salary defined in the framework.
local PayTable = {
    unemployed = { [0] = 50 },
    police     = { [0] = 250, [1] = 350, [2] = 500, [3] = 800 },
    ambulance  = { [0] = 220, [1] = 320, [2] = 480, [3] = 750 },
    mechanic   = { [0] = 180, [1] = 260, [2] = 400 },
}

local function resolveSalary(job, grade)
    -- Prefer the framework-defined grade salary, then our fallback, then 0.
    if job.grade_salary and job.grade_salary > 0 then
        return job.grade_salary
    end
    local byJob = PayTable[job.name]
    if byJob and byJob[job.grade] then
        return byJob[job.grade]
    end
    return 0
end

CreateThread(function()
    while true do
        Wait(PAY_INTERVAL)
        local xPlayers = ESX.GetExtendedPlayers()
        for _, xPlayer in pairs(xPlayers) do
            local job = xPlayer.getJob()
            local salary = resolveSalary(job, job.grade)
            if salary > 0 then
                xPlayer.addAccountMoney("bank", salary)
                TriggerClientEvent("paycheck:received", xPlayer.source, salary, job.label)
            end
        end
    end
end)

-- ===== client.lua =====
RegisterNetEvent("paycheck:received", function(amount, jobLabel)
    local ESX = exports['es_extended']:getSharedObject()
    ESX.ShowNotification(("Paycheck: ~g~$%d~s~ deposited (%s)"):format(amount, jobLabel))
end)

Known Failure Modes

  • Client-side payout — paying from the client lets anyone forge their own salary. Require the entire loop in the server section.
  • Wrong iteratorGetPlayers() yields id strings, not xPlayer objects; calling .addAccountMoney on them errors. Require ESX.GetExtendedPlayers().
  • Missing-grade zero pay — a sparse salary table with no fallback silently pays nothing. Require a resolveSalary fallback chain.
  • Instant-fire on start — looping with Wait at the end pays everyone immediately on resource start. Require Wait first.

Integration Notes

Put the loop in server.lua and the notifier in client.lua; declare both in fxmanifest.lua with server_script / client_script. Depends on es_extended. To test fast, drop PAY_INTERVAL to 15 * 1000, /setjob police 2, wait, and confirm the bank account rises by the grade-2 amount and the notification fires.

Profit Potential

$150–$1800/mo on Tebex (expected ~$500). [INFERRED] priced inside the $50-389 standalone-script band against the signal-scraper corpus (tebex_snapshot n=100, median seller $11.85K/mo) for a rising economy niche.

Trend Signal

rising — [INFERRED] banking/economy is core RP-server infrastructure, steady demand.

Sales Angle

Position as the dependable passive-income heartbeat for ESX economies — grade-aware payouts on a server timer with a safe fallback table, ready to pair with tax and salary-tier add-ons. Recommended Tebex price: $59.

Difficulty & Ship Time

beginner · ships in 1-3h.