How to add license keys to a FiveM script
Short answer: put the one-file SunLicense Lua SDK in your resource, read the server owner's key from a convar in server.cfg, check it server-side when the resource starts, and start your features only when SunLicense says yes. A network error is not a no: keep running and check again later. Ship it through Tebex's asset escrow.
-- server/license.lua (server_scripts in fxmanifest.lua)
local resource = GetCurrentResourceName()
local SunLicense = load(LoadResourceFile(resource, 'lib/sunlicense.lua'), '@lib/sunlicense.lua')()
local client = SunLicense.new({ baseUrl = 'https://api.sunlicense.com', token = SunLicenseSettings.apiKey })
client:validate(GetConvar('my_resource_license', ''), { host = serverId() }, function(ok, status, body)
if status == 400 then -- EXPIRED, REVOKED, TOO_MANY_MACHINES...: body has the code
print(('^1[%s] License rejected: %s^7'):format(resource, body))
return
end
if not ok then print(('^3[%s] SunLicense unreachable, starting anyway^7'):format(resource)) end
StartMyFeatures()
end)The SDK uses FiveM's PerformHttpRequest, so the server never waits for the answer.
Start from the template instead: example-fivem-resource (Lua 5.4, RedM too) has this plus a stable server id, masked keys, re-checks every 6 hours, a sealed server/core.lua that only runs with a valid license, a packaging script for Tebex escrow, tests and CI. All templates.
Or let your AI agent do it: paste the setup prompt into your coding agent.
Free plan: 3 products, 100 licenses, no credit card. Create a free account.
Step by step
- In the dashboard: a product, a policy (a machine is a server) and an API key, which can only validate. Integrations → Tebex issues a key per package sale and revokes it on a chargeback.
- The SDK is one file: copy
sunlicense.luafrom sunlicense-com/sunlicense-lua tolib/sunlicense.lua. FiveM has norequire, so load it withLoadResourceFileas above, server-side only. - The server owner's key goes in
server.cfg:set my_resource_license "AX8P-…". Useset, notsetr, so it isn't replicated to clients. - Your API key goes into
settings.luaat packaging time (the template'sscripts/package.shfills it from your environment), never in git. - Server id: a FiveM resource can only write inside its own folder, so keep one random id there with
SaveResourceFile(resource, '.machine-id', id, -1)and reuse it (the template'sserverId()). - Results: 200 starts your features, 400 leaves them off with the reason (mask the key in the console), anything else starts them and retries in about 10 minutes (
SetTimeout(600000, …)). Re-check every few hours so a revoked key reaches running servers. - Escrow. Upload the resource through Tebex's asset escrow (Cfx.re keymaster) so buyers can't read or edit the check,
settings.luaor your code; keep config files you want buyers to edit inescrow_ignore.
Cfx.re and Tebex rules
FiveM and RedM run under Rockstar's Creator Platform License Agreement (last updated 10 September 2026). It lets Rockstar name authorized or exclusive e-commerce, payment and marketplace providers and require you to use them; for FiveM that is Tebex, with asset escrow for paid resources, and the list is on fivem.net. Selling your own resources is fine; running a store that resells other creators' resources is one of the prohibited methods (section 3.1). A license check only decides whether your own resource runs on a server, and changes none of this. The agreement and the list of authorized services change from time to time: read both before you list.
Going further
- Obfuscation for Lua (Prometheus) and protection (the template seals
server/core.lua). - Product analytics: which framework, server builds and versions your buyers run.
- Writing it in C#? The .NET SDK works in CitizenFX. More on licensing FiveM scripts.
