Configuration
Core settings live in shared/config.lua. Each app area has its own file in shared/config/:
| File | Table | Covers |
|---|---|---|
shared/config.lua | Config.* | Framework, voice, keys, item, number format, walk mode, prop and animation, weather, uploads, App Store, rate limit, settings |
shared/config/comms.lua | Config.Comms | Calls, ringtone, payphones, contacts, messages, Darkchat |
shared/config/city.lua | Config.City | Wallet, mail, garage, groups, job center |
shared/config/social.lua | Config.Social | Chirp, Yellow Pages, businesses, maps, calendar, stocks, transit, news |
shared/config/media.lua | Config.Media | Allowed image hosts, AirDrop, photos, camera, notes, files |
Secrets
Config files are shared with clients. Upload tokens, webhooks and the passcode pepper are read from server convars. See Installation → Secrets.
Core
| Option | Default | Description |
|---|---|---|
Config.Framework | 'auto' | 'qbx', 'qb', 'esx', or auto-detect (qbx → qb → esx) |
Config.Voice | 'auto' | 'pma-voice', 'saltychat', 'yaca', 'none', or auto-detect. Without voice, calls are UI-only |
Config.VoiceCallChannelOffset | 10000 | pma-voice only: phone calls use channel offset + callId, away from channels other scripts use |
Config.OpenKey / Config.Command | 'F1' / 'phone' | Default key binding (rebindable) and command |
Config.CallKeys | { accept = 'Y', decline = 'BACK' } | Ring-mode keys while the phone is put away. false disables a key |
Config.KeepAppMinutes | 5 | Minutes the open app stays mounted under the lock screen (0 = close on lock) |
Config.RequireItem / Config.ItemNames | false / { 'phone' } | Require one of these items to open and use the phone. Uses ox_inventory if started, otherwise the framework inventory |
Config.NumberFormat | '555-####' | Phone number pattern, # = random digit. Keep at least 4 # |
Config.ShowServerId | true | Server ID next to the clock (hidden in streamer mode) |
Config.Locale | 'en' | NUI language |
Config.NoPhoneText | "You don't have a phone." | Feed message when the item is missing |
Config.WalkMode | true | Keep walking and driving while the phone is open. Keyboard focus only while typing |
Config.DisabledControls | camera, attack, weapon wheel, pause, chat, … | Controls disabled every frame while the phone is open in walk mode |
Config.Prop | prop_npc_phone_02 on bone 28422 | Hand prop: model, bone, offset, rotation |
Config.Anim | cellphone@, in-car anim@cellphone@in_car@ps | text and call enter / base / exit clips |
Config.WeatherCity / Config.Weather | 'Los Santos' / per GTA weather type | Widget label and °C per weather type (GTA has no temperature) |
Config.NotifySound | Text_Arrive_Tone | Frontend sound for notifications while the phone is closed |
Config.Upload | fivemanage | Photo upload provider: 'fivemanage', 'discord', 'none'. Token and webhook come from convars |
Config.StoreApps | { { id = 'darkchat', item = 'vpn' } } | App Store gating (see below) |
Config.RateLimit | { perSecond = 15, burst = 40 } | Per-player server RPC token bucket |
Config.EnforcePasscode | false | Reject app RPCs until a passcode-protected phone is unlocked |
Config.Settings | Allowed player settings keys and types, defaults, size limit | |
Config.Debug | false | Verbose logging |
App Store gating
Apps that aren't listed can be installed freely.
lua
Config.StoreApps = {
{ id = 'darkchat', item = 'vpn' }, -- needs the item
{ id = 'mdt', job = 'police' }, -- needs the job
{ id = 'mdt', job = { 'police', 'sheriff' }, grade = 2, onduty = true }, -- list, min grade, on duty
}Other resources can add entries at runtime with exports.np_phone:registerStoreApp(entry) (see Exports).
Player settings
lua
Config.Settings = {
maxBytes = 16384, -- max size of a player's settings JSON
allowUnknown = true, -- accept keys not listed below (^[%a][%w_]*$, ≤ 32 chars)
keys = { wallpaper = 'string', volume = 'number', dnd = 'boolean', homeOrder = 'table', --[[ ... ]] },
defaults = { theme = 'dark', wallpaper = 'clouds', ringtone = 'Reflection', volume = 0.6, use24h = true, --[[ ... ]] },
}Comms (Config.Comms)
| Option | Default | Description |
|---|---|---|
ringTimeout | 30 | Seconds an outgoing call rings before it counts as missed |
ringtone | Remote_Ring / Phone_SoundSet_Michael | Frontend sound. Nearby players hear it in 3D (state bag np_phoneRinging) |
ringRange / ringInterval | 25.0 / 3500 | 3D ringtone range (m), re-trigger interval (ms) |
hiddenPrefix | '#31#' | Hides the caller ID for one call |
payphones | true | Walk up to a payphoneModels prop, press E, dial |
payphoneDistance / payphoneCost / payphoneKey | 1.6 / 5 / 38 (E) | |
maxContacts | 500 | |
shareDistance / shareTimeout | 3.0 / 60 | Contact sharing range (m) and prompt lifetime (s) |
maxMessageLength / maxGroupMembers / pageSize | 1000 / 16 / 50 | |
liveLocationMinutes / liveLocationInterval | { 15, 30, 60 } / 5000 | Offered durations; ms between updates |
maxTransfer | 1000000 | Max in-chat money transfer |
darkchatTTLHours / darkchatMaxChannels / darkchatMaxLength | 24 / 20 / 500 |
City (Config.City)
| Option | Default | Description |
|---|---|---|
bankName / cardBrand | 'Fleeca' / 'VISA' | Shown on the wallet card |
maxTransfer | 1000000 | Max single transfer, request or invoice |
allowDeclineInvoices | false | Business invoices and fines can't be declined (payment requests always can) |
overdueWarnDays | 3 | Invoices due within N days show a banner |
invoicePayout | nil | function(invoice) called after a business invoice is paid. Credit the society account here |
mailDomain | 'lsmail.com' | Player addresses are first.last@<mailDomain> |
govSenders | LSPD, City Hall, DOJ, … | Senders whose mail lands in the "Gov" folder |
valetFee / impoundFee | 150 / 600 | |
valetSpawn | false | Built-in valet spawn. Keep false when your garage script handles np_phone:garage:valet |
impoundReleaseDb | true | qb/qbx: set player_vehicles.state = 1 on release |
garages / defaultGarage / impound | Garage name → label and coords (waypoints) | |
groupMaxMembers / groupInviteTimeout / groupNearbyRadius | 6 / 120 / 10.0 | |
groupJobs | sanitation, delivery, fishing | Jobs listed under "Available" in Groups |
demoJob | { enabled = false } | /np_phone_demojob to try the group job API. Never enable it on a live server |
jobCenter / applyCooldown | 5 civilian jobs / 60 | Job center entries; "Apply" sends a mail with a waypoint |
Example society payout:
lua
invoicePayout = function(invoice)
if invoice.senderJob then exports['Renewed-Banking']:addAccountMoney(invoice.senderJob, invoice.amount) end
end,Social (Config.Social)
| Option | Default | Description |
|---|---|---|
verifiedJobs | police, ambulance, news, … | Chirp verified badge while on that job |
chirp | maxLength = 280, maxImages = 4, anonymousTips = true, … | |
ypPostFee / ypExpireHours / ypMaxActivePerPlayer | 50 / 48 / 5 | Yellow Pages ads |
ypCategories | vehicles, homes, services, items, other | |
businesses / businessCacheSeconds | 9 businesses / 15 | "Open now": open while a player with that job is on duty |
pois / placeIcons / maxPlaces | Maps | |
calendarMaxEvents / calendarReminderCheck / calendarMaxInvites | 200 / 60 / 10 | |
stockTickMinutes / stockHistory / stocks | 10 / 48 / 7 symbols | Random-walk prices. crypto = true allows 4 decimals |
transit | ticket price, lines and stops | Departures computed from the in-game clock |
newsJobs / newsNotifyAll | { 'news', 'weazel' } / false | Who can publish; Breaking News notification to everyone |
Media (Config.Media)
| Option | Default | Description |
|---|---|---|
allowedHosts | FiveManage, Discord CDN | Image URLs players can save or show to others must be https on one of these hosts (or a subdomain). Add your custom CDN domain |
share | distance = 3.0, timeout = 45, maxPendingPerTarget = 3, label = 'contact' | AirDrop. label = 'name' shows character names (metagaming risk) |
photos | max = 500, pageSize = 60, maxAlbums = 30 | |
camera | encoding = 'webp', quality = 0.85, cooldown = 1500, … | allowDiscordClientUpload = false (see Upload security), keys |
notes | max = 300, maxLength = 20000, maxFolders = 30 | |
files | max = 500, maxBody = 20000, types |