🆔ID CARD
A comprehensive ID card system for ESX Legacy servers featuring passport, driver license, weapon license, and custom card types. Includes photo capture system with Discord/FiveManage integration.







Features
Multiple Card Types: Passport, Driver License, Weapon License, Cayo Card, Police Badge, Job Badges
Photo System: Take and store player photos for ID cards
Show Cards: Display cards to nearby players with animations (automatically finds closest player)
Export System: Easy integration with other resources
Secure API: Server-side credential protection for image uploads
Customizable: Extensive configuration options
Job Badge System: Automatic job detection and custom badge display for all jobs
Requirements
esx_license (for licenses)
screenshot-basic (for photo capture)
Installation
Download and extract the resource to your
resourcesfolderAdd
ensure idcardto yourserver.cfgMake sure you have the required dependencies installed
Configure the resource (see Configuration section)
Configuration
Main Configuration (shared/_main.lua)
shared/_main.lua)Commands
PHOTO.Config.Commands = {
openCard = "openCard", -- Command to open your own card
showCard = "showCard", -- Command to show card to nearby player
closeCard = "closeCard", -- Command to close opened card
takePicture = "takePicture" -- Command to take ID photo, can be disable
}Show Card Distance
PHOTO.Config.ShowCardDistance = 3.0 -- Maximum distance in meters to show card to another playerCard Animation
PHOTO.Config.ShowCardAnimation = {
enabled = true,
mode = "emote", -- "emote" (uses external emote script) or "custom" (built-in animations)
emoteCommand = "card", -- Emote command name (will be "/e card")
-- Custom mode settings (only used if mode = "custom")
dict = "paper_1_rcm_alt1-9",
anim = "player_one_dual-9",
propBone = 28422,
cardConfigs = {
passport = { prop = "prop_pass_badge", placement = {...} },
driver = { prop = "prop_driver_badge", placement = {...} },
weapon = { prop = "prop_weapon_badge", placement = {...} },
-- ... more card types
}
}License Configuration
PHOTO.Config.Licenses = {
car = {
dbName = "car", -- Must match EXACTLY the type in your user_licenses table
icon = "car", -- Font Awesome icon (without "fa-" prefix)
category = "driver" -- Category for grouping licenses
},
-- Add more licenses as needed
}Important: The dbName must match EXACTLY the license types in your user_licenses table.
API Configuration (shared/api.lua)
shared/api.lua)⚠️ This file is loaded server-side only for security!
Export Type
PHOTO.Export.Config = {
type = "discord", -- "discord" or "fivemange"
-- FiveManage API (if type = "fivemange")
fivemange = {
apiKey = "YOUR_API_KEY",
apiUrl = "https://fmapi.net/api/v2/image"
},
-- Discord Webhook (if type = "discord")
discord = {
webhook = "YOUR_DISCORD_WEBHOOK_URL"
}
}Commands
/openCard [type]
/openCard [type]Opens your own ID card.
Types: passport, driver, weapon, cayo, police, job, or any configured job name
Examples:
/openCard- Opens passport (default)/openCard driver- Opens driver license/openCard weapon- Opens weapon license/openCard cayo- Opens cayo card/openCard police- Opens police badge (if you're a police officer)/openCard job- Opens your job badge (automatically detects your job)/openCard mechanic- Opens mechanic badge (if you're a mechanic)
/showCard [type]
/showCard [type]Shows your ID card to the closest player within 3 meters.
Types: passport, driver, weapon, cayo, police, job, or any configured job name
Examples:
/showCard driver- Shows driver license to nearby player/showCard weapon- Shows weapon license to nearby player/showCard police- Shows police badge to nearby player (if you're a police officer)/showCard job- Shows your job badge to nearby player (automatically detects your job)/showCard mechanic- Shows mechanic badge to nearby player (if you're a mechanic)
/closeCard
/closeCardCloses the currently opened ID card.
/takePicture
/takePictureOpens the photo capture menu to take a new ID photo.
Note: This command can be disabled by setting PHOTO.Config.EnableTakePicture = false
Exports
Client-Side Exports
GetCardId()
Returns the URL of the player's ID card photo.
Returns: string - Photo URL or nil if no photo exists
Example:
local photoUrl = exports['idcard']:GetCardId()
if photoUrl then
print("Photo URL: " .. photoUrl)
else
print("No photo found")
endOpenCard(cardType)
Opens a specific card type for the current player.
Parameters:
cardType(string, optional): Card type ("passport","driver","weapon","cayo","police","job", or any configured job name). Defaults to"passport".If
"job"is specified, automatically detects the player's current job and shows the corresponding badge.
Returns: boolean - true if successful, false if invalid card type
Examples:
-- Open passport
exports['idcard']:OpenCard('passport')
-- Open driver license
exports['idcard']:OpenCard('driver')
-- Open weapon license
exports['idcard']:OpenCard('weapon')
-- Open job badge (automatically detects your job)
exports['idcard']:OpenCard('job')
-- Open specific job badge
exports['idcard']:OpenCard('mechanic')
exports['idcard']:OpenCard('police')ShowCard(cardType, targetPlayerId)
Shows a card to another player. Automatically finds the closest player within configured distance if no target is specified.
Parameters:
cardType(string, optional): Card type ("passport","driver","weapon","cayo","police","job", or any configured job name). If only one parameter is provided, it's treated as cardType and automatically finds closest player.If
"job"is specified, automatically detects the player's current job and shows the corresponding badge.
targetPlayerId(number, optional): Target player's server ID. If not provided, automatically finds closest player within configured distance (default: 3 meters).
Returns: boolean - true if successful, false if no player found or invalid card type
Examples:
-- Automatically find closest player within 3m and show driver license
exports['idcard']:ShowCard('driver')
-- Show weapon license to specific player
exports['idcard']:ShowCard(5, 'weapon')
-- Show passport to specific player
local targetId = GetPlayerServerId(targetPlayer)
exports['idcard']:ShowCard(targetId, 'passport')
-- Show job badge to closest player (automatically detects your job)
exports['idcard']:ShowCard('job')
-- Show specific job badge to closest player
exports['idcard']:ShowCard('mechanic')
-- Show job badge to specific player
local targetId = GetPlayerServerId(targetPlayer)
exports['idcard']:ShowCard(targetId, 'job')Server Events
idcard:open
idcard:openOpens an ID card for a player.
Parameters:
sourcePlayerId(number): Server ID of the player showing the cardtargetPlayerId(number): Server ID of the player viewing the cardcardType(string, optional): Card type ("passport","driver","weapon","cayo"). Defaults to"passport".photoUrl(string, optional): Photo URL. If not provided, uses stored photo.
Example:
-- Show your own passport
TriggerServerEvent('idcard:open', GetPlayerServerId(PlayerId()), GetPlayerServerId(PlayerId()), 'passport')
-- Show driver license to closest player
local player, distance = ESX.Game.GetClosestPlayer()
if distance ~= -1 and distance <= 3.0 then
TriggerServerEvent('idcard:open', GetPlayerServerId(PlayerId()), GetPlayerServerId(player), 'driver')
endUsage Examples
Basic Menu Integration
-- In your menu script
RegisterCommand('idmenu', function()
ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'id_menu', {
title = 'ID Card Menu',
elements = {
{label = 'View Passport', value = 'passport'},
{label = 'View Driver License', value = 'driver'},
{label = 'View Weapon License', value = 'weapon'},
{label = 'Show Passport', value = 'show_passport'},
{label = 'Show Driver License', value = 'show_driver'},
}
}, function(data, menu)
local value = data.current.value
if value == 'passport' then
exports['idcard']:OpenCard('passport')
elseif value == 'driver' then
exports['idcard']:OpenCard('driver')
elseif value == 'weapon' then
exports['idcard']:OpenCard('weapon')
elseif value == 'show_passport' then
exports['idcard']:ShowCard('passport')
elseif value == 'show_driver' then
exports['idcard']:ShowCard('driver')
end
menu.close()
end, function(data, menu)
menu.close()
end)
end)Police Script Example
-- Check player's driver license
RegisterCommand('checklicense', function(source, args)
local targetPlayer = tonumber(args[1])
if targetPlayer then
exports['idcard']:ShowCard(targetPlayer, 'driver')
else
-- Automatically find closest player
exports['idcard']:ShowCard('driver')
end
end)
-- Check weapon license
RegisterCommand('checkweapon', function()
exports['idcard']:ShowCard('weapon')
end)Vehicle Script Example
-- Show driver license when entering vehicle
AddEventHandler('esx:enteringVehicle', function(vehicle, seat, vehicleName)
exports['idcard']:OpenCard('driver')
end)RageUI Menu Integration Example
-- Show passport button
RageUI.ButtonWithStyle("Identity Card - San Andreas", "Show | Look", {}, true, function(Hovered, Active, Selected)
if (Selected) then
ESX.TriggerServerCallback('rs_menu:HasItem', function(result)
if result then
local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer(nil, IgnorePlayersInSideVehicules)
if closestDistance ~= -1 and closestDistance <= 3.0 then
-- Show card to closest player
TriggerServerEvent('idcard:open', GetPlayerServerId(PlayerId()), GetPlayerServerId(closestPlayer), 'passport', cardId)
else
-- Show card to yourself if no one nearby
TriggerServerEvent('idcard:open', GetPlayerServerId(PlayerId()), GetPlayerServerId(PlayerId()), 'passport', cardId)
end
ExecuteCommand("e card")
else
ESX.ShowNotification("You do not have an ID card!")
end
end, "idcard1")
RageUI.CloseAll()
endUsing Exports with Job Cards
-- Open your own job badge (automatically detects your job)
exports['idcard']:OpenCard('job')
-- Show your job badge to closest player
exports['idcard']:ShowCard('job')
-- Show specific job badge (e.g., mechanic) to closest player
exports['idcard']:ShowCard('mechanic')
-- Show job badge to specific player
local targetPlayerId = GetPlayerServerId(targetPlayer)
exports['idcard']:ShowCard(targetPlayerId, 'job')Custom Photo Check
-- Check if player has a photo
local function hasPhoto()
local photoUrl = exports['idcard']:GetCardId()
return photoUrl ~= nil and photoUrl ~= ""
end
-- Use in your script
if hasPhoto() then
print("Player has a photo")
else
print("Player needs to take a photo")
endCard Types
Passport
Shows: Firstname, Lastname, Date of Birth, Sex, Height, Nationality
Always available (no license required)
Driver License
Shows: Same as passport + Driver licenses (car, bike, boat, truck, etc.)
Requires: At least one driver license in
user_licensestable
Weapon License
Shows: Same as passport + Weapon license
Requires: Weapon license in
user_licensestable
Cayo Card
Shows: Same as passport + Cayo license
Requires: Cayo license in
user_licensestable
Photo System
Taking a Photo
Use
/takePicturecommand or triggerscreenshot:takePictureeventPlayer is teleported to photo studio
Photo is captured using
screenshot-basicPhoto is uploaded to Discord/FiveManage (configured in
shared/api.lua)Photo URL is stored in FiveM KVP and displayed on all cards
Photo Storage
Photos are stored in FiveM Key-Value Pairs (KVP) as
cardIdPhoto URL is retrieved on resource start
Photo URL is sent with card data when opening cards
Photo Upload Services
Discord Webhook
Uploads photo to Discord channel via webhook
Returns Discord attachment URL
Configure webhook URL in
shared/api.lua
FiveManage API
Uploads photo to FiveManage image hosting
Requires API key
Configure API key and URL in
shared/api.lua
Security Note: API keys and webhooks are stored server-side only in shared/api.lua to prevent client-side access.
Database Structure
Required Tables
users table
Must contain:
identifier(string): Player identifierfirstname(string): Player first namelastname(string): Player last namedateofbirth(string): Date of birth (format: DD/MM/YYYY or DD-MM-YYYY)sex(string): "m" or "f"height(number): Height in cm
user_licenses table
Must contain:
owner(string): Player identifier (must matchusers.identifier)type(string): License type (must matchPHOTO.Config.Licenses[].dbName)
Important: The owner field format must match your ESX configuration (usually char1:identifier or just identifier).
Cache System
The resource uses a server-side caching system to optimize database queries and improve performance.
How It Works
Automatic Caching: Player data (identity, licenses, job) is cached when first accessed
Cache Lifecycle: Cache is created when a player opens/shows a card and persists until the player disconnects
Cache Refresh: Cache is automatically refreshed when needed (e.g., when player data changes)
Memory Management: Cache is automatically cleared when a player disconnects
Cache Contents
The cache stores:
User Data: Firstname, lastname, date of birth, sex, height
Licenses: All licenses from
user_licensestableJob Data: Current job name, label, grade, and grade information
Manual Cache Refresh
If you need to refresh a player's cache manually (e.g., after granting a license), you can trigger:
-- Refresh cache for a specific player
TriggerEvent("idcard:refreshCache", source)Cache Events
idcard:refreshCache- Refreshes the cache for a specific playerAutomatically triggered on player disconnect to clean up memory
Performance Benefits
Reduces database queries by caching player data
Improves response time when opening/showing cards
Automatically manages memory by clearing cache on disconnect
Troubleshooting
Card doesn't show licenses
Check that license types in
PHOTO.Config.Licensesmatch exactly with your databaseVerify
ownerfield format matches your ESX setupCheck server console for cache errors
Try refreshing the cache:
TriggerEvent("idcard:refreshCache", source)
Photo doesn't upload
Verify API credentials in
shared/api.luaCheck that
screenshot-basicresource is startedCheck server console for upload errors
Card doesn't open
Ensure ESX is properly loaded
Check that player data is available
Verify card type is valid (
passport,driver,weapon,cayo)
Animation doesn't play
If using
emotemode, ensure emote script is installedIf using
custommode, verify animation dictionaries are loadedCheck
PHOTO.Config.ShowCardAnimation.enabledistrue
Last updated