Commands#
Licenses Creator registers two in-game commands. Players never need one: licenses are bought at peds and shown by using the item.
Command | Description |
|---|---|
| Opens the creator — or closes it if it is open. Needs creator access. |
| Opens the creator straight on the Peds tab, to move peds and blips. |
Both names are set in Config.Creator in shared/config.lua. Access is checked on the server every time, so renaming a command never opens it to more people.
Client Exports#
For opening the interface from your own scripts — a laptop prop in the police station, a radial menu entry, a tablet app.
OpenPanel / ClosePanel / IsPanelOpen
exports['qs-licensescreator']:OpenPanel({ key = 'global:2' }) -- what that ped opens
exports['qs-licensescreator']:OpenPanel() -- the creator
exports['qs-licensescreator']:ClosePanel()
local open = exports['qs-licensescreator']:IsPanelOpen() -- true while any panel or the creator is upA key opens exactly what that ped would — a license office, the authorization center or terminal, a forger — without walking to it. Keys are license:<id> for license offices and global:<id> for the others, using the row id from qs_licenses_interactions or qs_licenses_global_interactions. The ped's job and gang rules still apply.
OpenCreator / CloseCreator
exports['qs-licensescreator']:OpenCreator('issued') -- peds, licenses, designer, categories, issued, users, settings
exports['qs-licensescreator']:CloseCreator()Opens the creator on a given tab. The player still needs creator access; without it they are told they have no permission.
Server Exports#
How another resource drives Licenses Creator — an MDT that revokes, a driving school that grants, a traffic script that adds points. Wherever an export takes a licenseId, it accepts the template id ('driver_license'), the name ('Driver License') or the numeric template id. Wherever it takes a target, a number is a player's server id and a string is a citizen id — so offline citizens work too.
Checking licenses#
HasLicense
local valid = exports['qs-licensescreator']:HasLicense(citizenid, 'weapon_license')
-- true only if the license is active and not expiredThe check a gun shop, an airport or a hunting area should use. Cancelled, stolen, lost and expired licenses — and every fake card — answer false.
GetLicense
local license = exports['qs-licensescreator']:GetLicense(citizenid, 'driver_license')
-- {
-- id = 42, license_id = '5', template_id = 'driver_license', license_name = 'Driver License',
-- citizenid = 'ABC12345', generated_id = 'DMV-4821733', status = 'active', expired = false,
-- issued_at = '...', expires_at = '...', issued_by = 'Driving examiner',
-- photo_url = 'https://...', reported_at = nil, points = 4,
-- }The citizen's license of that kind — the active one if there is one, otherwise the latest — or nil. What an MDT shows on a citizen's record.
GetActiveLicenses
local list = exports['qs-licensescreator']:GetActiveLicenses(source) -- or a citizenid
-- { { template_id = 'id_Card', license_name = 'Identification Card', active = true }, ... }Every license the citizen holds that is valid right now.
Granting, revoking and reinstating#
AddLicenseToPlayer
local result = exports['qs-licensescreator']:AddLicenseToPlayer(source, 'driver_license')
-- { success = true, granted = 1, id = 42 } issued
-- { success = true, granted = 0 } already had it
-- { success = false, pending = true } photo capture started, it finishes by itselfIssues a license to an online player, free, as System — what a driving school calls when the test is passed. A player who has never had a photo taken is put through the camera first and the license follows on its own.
RevokeLicense
exports['qs-licensescreator']:RevokeLicense(citizenid, 'driver_license') -- by citizen and license
exports['qs-licensescreator']:RevokeLicense(42) -- by record id
exports['qs-licensescreator']:RevokeLicense('DMV-4821733') -- by document number
-- { success = true, message = 'revoked' }Sets the license to cancelled and logs it to Discord when cancellation logs are on. The item stays in the inventory, but the card now shows stamped Cancelled.
-- Revoking from an MDT
local result = exports['qs-licensescreator']:RevokeLicense(citizenid, 'driver_license')
if result.success then
TriggerClientEvent('QBCore:Notify', source, 'License revoked', 'success')
else
TriggerClientEvent('QBCore:Notify', source, result.message, 'error')
endActivateLicense
exports['qs-licensescreator']:ActivateLicense(citizenid, 'driver_license')
exports['qs-licensescreator']:ActivateLicense(42)
-- { success = true, message = 'activated' }Reinstates a cancelled license, or clears a stolen or lost report. It does not change the expiry date.
Penalty points#
AddLicensePoints / RemoveLicensePoints / SetLicensePoints / GetLicensePoints
local result = exports['qs-licensescreator']:AddLicensePoints(source, 'driver_license', 4)
-- { success = true, message = 'ok', points = 8 }
exports['qs-licensescreator']:RemoveLicensePoints(citizenid, 'driver_license', 2)
exports['qs-licensescreator']:SetLicensePoints(citizenid, 'driver_license', 0)
exports['qs-licensescreator']:GetLicensePoints(citizenid, 'driver_license')
-- by record id or document number, without a license id:
exports['qs-licensescreator']:AddLicensePoints('DMV-4821733', 3)Points never go below zero. Adding or setting points checks the threshold in server/custom/points.lua; when it is reached, this server event fires before the license is revoked or your own event is called, and the counter goes back to zero:
AddEventHandler('qs-licensescreator:server:pointsThresholdReached',
function(citizenid, issuedId, templateId, points, threshold)
-- a fine, a court date, a notification to the police...
end)
-- With action = 'event', your own event receives:
AddEventHandler('myresource:server:gunSuspended', function(citizenid, issuedId, templateId, points) end)Starter licenses#
RequestStarterLicenses
exports['qs-licensescreator']:RequestStarterLicenses(source)
-- { success = true, granted = 2 }
-- { success = false, pending = true } photo capture started
-- { success = false, message = 'photo_not_configured' }The whole starter flow in one call — the one to use from a character creator that is not hooked by default. Takes the photo if needed, then issues every starter license the player is missing.
GetStarterLicenses / CheckStarterLicensesNeeds / GrantStarterLicenses
local list = exports['qs-licensescreator']:GetStarterLicenses()
-- { { license_id = 'id_Card', display_name = 'Identification Card', id = 3 }, ... }
local needs = exports['qs-licensescreator']:CheckStarterLicensesNeeds(source)
-- { hasMissing = true, existingPhotoUrl = 'https://...', missingLicenseIds = { 'driver_license' } }
exports['qs-licensescreator']:GrantStarterLicenses(source, photoUrl) -- photoUrl optional
-- { success = true, granted = 1 }The same flow in pieces, for a script that takes its own photo or wants to decide when to grant.
Interface and items#
OpenPanel / ClosePanel
exports['qs-licensescreator']:OpenPanel(source, { key = 'license:2' }) -- a ped's panel
exports['qs-licensescreator']:OpenPanel(source, { tab = 'issued' }) -- the creator, on a tab
exports['qs-licensescreator']:ClosePanel(source)
-- true, or false if the player is not onlineThe server-side twins of the client exports. Access rules still apply on the player's side.
useLicense
exports['qs-licensescreator']:useLicense(source, item, slot)Shows the card of a license item exactly as using it would. For an inventory that has no used-item event the resource can hook. On ox_inventory the item definition calls qs-licensescreator.useLicenseItem instead.
RefreshLicenseTemplates
local count = exports['qs-licensescreator']:RefreshLicenseTemplates()Reloads the templates from the database and pushes them to every player — only needed after editing qs_licenses_templates by hand or from another script. Returns how many were loaded.
DebugGetTemplates / DebugGetInteractions
print(json.encode(exports['qs-licensescreator']:DebugGetTemplates()))
print(json.encode(exports['qs-licensescreator']:DebugGetInteractions()))What the server has in memory right now: every template, and every ped with its key, role, position and access lists.
About the Results#
Exports that change something return a table with success and a message. The messages you will meet:
Message | Means |
|---|---|
| That citizen has never held that license, or the record id or document number does not exist. |
| No template matches the license id, name or number given. |
| The player is offline, or the framework has not loaded their character yet. |
| The license is reported stolen or lost and cannot be reissued until the report is cleared. |
| The record was written but the item did not fit in the inventory. |
| A photo is needed and Settings → Photo upload is empty. |



