PlayDeck
Home / Course / Earning From a Server, Compliantly
Track B · Lesson 2

Earning From a Server, Compliantly

Most people assume earning from a FiveM server is either forbidden or a grey-market gamble. It's neither. There's a narrow, fully sanctioned path — and staying on it is about understanding one principle, not memorizing a rulebook. This lesson shows you the path, the wiring, and the single line you can never cross.

The only two sanctioned doors

Cfx (the team behind FiveM) allows server monetization, but only through channels it controls. As of now there are exactly two:

  1. Tebex — the long-standing storefront for selling server perks to your players (priority queue, cosmetic flair, supporter Discord roles).
  2. The Cfx Marketplace — added in January 2026, this is the sanctioned channel for selling creator assets and scripts to other developers.

Anything outside these — a PayPal link in your Discord, a "donate for cash" Ko-fi tied to in-game rewards, a third-party shop — is unsanctioned and is the fastest way to lose your server. The reason is simple: Cfx can only enforce its rules where it has visibility. Off-platform payments have none, so they're banned outright.

Rules shift. Treat everything in this lesson as principles, and always verify the current Cfx Platform License Agreement (PLA) before you charge a cent. The PLA is the source of truth; this lesson is the orientation.

What you can sell — and the line you can't cross

The accessible starting point is perks players want but that don't change gameplay power:

The principle behind all of these: you're selling convenience and identity, never advantage. That's the whole game.

The line you cannot cross is pay-to-win. The moment money buys in-game power — more cash, better guns, rarer cars, faster XP, anything that makes a paying player beat a non-paying one — you've broken the PLA. Alongside that, these are flatly prohibited:

A useful gut check: if a non-paying player can be beaten by a paying one because of the purchase, it's pay-to-win. Priority queue passes. "Buy $50k in-game" fails instantly.

Wiring up Tebex

Tebex is the practical first step for server perks. The flow:

  1. Create a Tebex store and connect it to your server. Tebex gives you a secret key.
  2. In your server.cfg, set that key:
   set sv_tebexSecret "your-secret-key-here"

This is what links a real purchase to your server. Keep it out of public configs and Git — treat it like a password, because it is one.

  1. ID verification: at checkout, Tebex needs to know who bought the package, so the player verifies their FiveM/Cfx identity (their license: identifier). That identifier is how your server knows who to reward.
  2. Store review: before packages go live, your store and packages are reviewed for PLA compliance. Don't try to sneak pay-to-win past review — design compliant from the start and review is a formality.

On purchase, Tebex sends a command to your server console to grant the perk. The exact resource and command names change, so link to the official Tebex and Cfx docs and follow their current setup rather than copying any tutorial's snippet verbatim.

Server-side, or it isn't real

Here's where most beginners — and most AI-generated code — get it dangerously wrong: they trust the client. If your script lets the game client say "I bought priority, let me in," anyone can fake that message for free. Your monetization becomes optional.

The rule is absolute: the server is the only source of truth. Tebex writes the entitlement to the server. The server resolves who the player is. The client only ever asks and displays.

-- server.lua — resource: pd_perks
-- Compliant perks: an entitlement store written ONLY by Tebex,
-- read by clients through a callback. The client grants itself nothing.

local entitlements = {}  -- entitlements["license:abc"] = { priority = true }

-- Resolve identity on the SERVER. Whatever the client claims is untrusted.
local function getLicense(src)
    for _, id in ipairs(GetPlayerIdentifiers(src)) do
        if id:sub(1, 8) == 'license:' then return id end
    end
end

-- Tebex calls this from the server console on purchase.
-- source == 0 means "from console" — players can never trigger it themselves.
RegisterCommand('pd_grant', function(source, args)
    if source ~= 0 then return end -- security: reject anything not from console
    local license, perk = args[1], args[2]
    if not license or not perk then return end
    entitlements[license] = entitlements[license] or {}
    entitlements[license][perk] = true
    -- Persist to your DB here (oxmysql) so grants survive a restart.
end, true)

-- ox_lib server callback: client asks "do I own this perk?", server answers.
-- Validation lives here, on the server, never on the client.
lib.callback.register('pd_perks:owns', function(source, perk)
    local license = getLicense(source)
    return license ~= nil
        and entitlements[license] ~= nil
        and entitlements[license][perk] == true
end)

This uses lib.callback from ox_lib — the modern callback system — not the deprecated TriggerServerCallback patterns AI loves to hallucinate. When you ask AI to write monetization code, expect three failures: it invents fake exports, it mixes QBCore/Qbox/ESX in one file, and it validates on the client. Pin one framework (we teach Qbox/QBCore + ox), verify every native and export against the real reference, and test the grant flow in the PlayDeck sandbox before it touches real money.

Yes, it's taxable income

This is the part nobody mentions: money from your store is income, and most jurisdictions tax it. Tebex payouts, marketplace sales — it counts. Keep records of what comes in and what you spend (server hosting, asset licenses). If earnings become meaningful, talk to a local tax professional. Treating it as "internet pocket money" is how a fun project turns into a problem with your tax authority. Compliant earning means compliant with the law too, not just the PLA.

Practice

This week: open the current Cfx PLA and the Tebex docs side by side. Write down three perks you'd sell and, next to each, one sentence on why it isn't pay-to-win. If you can't write that sentence cleanly, cut the perk. Then set sv_tebexSecret in a private test server.cfg and confirm a test grant lands server-side using the callback pattern above — never trust the client to report its own purchase.

Recap

Learn it by building it

PlayDeck is an original course on building GTA roleplay scripts with AI — Lua, frameworks, NUI, debugging, and a browser sandbox to test every lesson without booting the game.

Browse the course