QBESXStandalone
Agency-Phone Configuração
Agora com o AgencyOS27: uma atualização grátis para quem já tem o telefone.
v27.1.2Pago8 Páginas

01Configuração
Instalação rápida · config.lua · Agency-Phone
--[[
╔══════════════════════════════════════════════════════════════════════╗
║ AGENCY PHONE - CONFIGURATION ║
║ (c) Agency Scripts ║
╚══════════════════════════════════════════════════════════════════════╝
CONTENTS
1. Core Framework, banking, language, data, debug
2. Controls Phone item, keys, commands
3. Phone Prop The model held in the hand during a call
4. Integrations Agency HUD, Notify, Reports, LifeInvader, Companion
5. Calls & Voice Calls, dialer, voice, walkie-talkie, payphones, video
6. Emergency MDT and dispatch
7. Network eSIM carrier plans and billing
8. Security Face Unlock, lock screen
9. Camera & Media Media storage, camera, video, screen capture, cloud
10. Communication Buzz, contacts, mail, Pulse, Bleeter, Snapr
11. Music & Radio Music library, review, GTA radio
12. Finance Wallet, Agency Pay, crypto, stocks, gambling
13. Darknet Market, levels, items, dead drops
14. Vehicles & Rides Garage, AutoRide
15. Jobs & Services Job apps, job listings, Agency Eats, maps
16. Angy Built-in assistant (fixed rules, no AI)
17. Logging Discord webhooks (addresses in config_server.lua)
18. Apps App Store, protected apps, app list
Keys, tokens and webhook addresses go into config_server.lua, which is
never sent to players.
]]
AgencyConfig = {}
--==============================================================================
-- 1 · CORE
--==============================================================================
-- ── Framework ────────────────────────────────────────────────────────────────
-- 'auto' = detect QBCore or ESX
-- 'qb' / 'esx' = force a framework
-- 'standalone' = no framework
-- 'oxide-banking' = alias for QBCore + Oxide banking
AgencyConfig.Framework = 'qb'
-- Only used in standalone mode.
AgencyConfig.Standalone = {
DefaultBankBalance = 5000, -- bank balance of a new player
}
-- ── Banking ──────────────────────────────────────────────────────────────────
AgencyConfig.Banking = 'framework' -- 'framework' | 'oxide-banking' (QBCore only)
AgencyConfig.InvoiceProvider = 'auto' -- 'auto' | 'okokBilling' | 'builtin'
-- ── Language & data ──────────────────────────────────────────────────────────
AgencyConfig.DefaultLanguage = 'en' -- 'en' | 'de' | 'fr' | 'es' | 'tr' | 'pl'
AgencyConfig.DataStorageMode = 'phone' -- 'phone' = data per phone number, 'person' = per character
AgencyConfig.AutoApplySqlSchema = true -- create the tables from agency-phone.sql on start
AgencyConfig.PerformanceModeDefault = false -- performance mode for new players
-- ── Debug ────────────────────────────────────────────────────────────────────
-- Prints diagnostics to the server console (NUI state, open-phone checks,
-- keybinds, radio textures). Meant for support cases, keep false when live.
AgencyConfig.Debug = false
--==============================================================================
-- 2 · CONTROLS
--==============================================================================
-- Keys use FiveM key names: 'M', 'F1', 'UP', 'OEM_4' ...
-- https://docs.fivem.net/docs/game-references/input-mapper-parameter-ids/keyboard/
-- These are the starting keys; players can rebind them under
-- Settings > Key Bindings > FiveM. Changing one here resets it for everyone.
-- false = no key (the command still works).
-- Note: qb-radialmenu also uses F1. The console reports such clashes.
AgencyConfig.PhoneItem = 'phone' -- item the player needs in the inventory
AgencyConfig.OpenKey = 'M' -- opens the phone
AgencyConfig.OpenCommand = 'phone' -- chat command that opens the phone (without /)
AgencyConfig.AnswerKey = 'Y' -- answers a call
AgencyConfig.DeclineKey = 'J' -- declines or ends a call
AgencyConfig.AngyKey = 'P' -- opens Angy directly
AgencyConfig.AllowMovement = true -- walk while the phone is open
--==============================================================================
-- 3 · PHONE PROP
--==============================================================================
-- The model the character holds during a call.
-- model : default prop (streamed by agency-phone itself, stream/)
-- fallback : used if the model is missing, keep this a vanilla prop
-- bone : ped bone, 28422 = right hand
-- pos/rot : fine-tune the position in the hand
-- models : one prop per frame finish (Settings > Appearance)
-- Custom models: the resource streaming them must start BEFORE agency-phone,
-- and only use models you are licensed to use.
AgencyConfig.PhoneProp = {
model = 'agency_phone_silver',
fallback = 'prop_npc_phone_02',
bone = 28422,
pos = { x = 0.0, y = 0.0, z = 0.0 },
rot = { x = 0.0, y = 0.0, z = 0.0 },
models = {
silver = 'agency_phone_silver',
graphite = 'agency_phone_graphite',
starlight = 'agency_phone_starlight',
blue = 'agency_phone_blue',
desert = 'agency_phone_desert',
green = 'agency_phone_green',
pink = 'agency_phone_pink',
violet = 'agency_phone_violet',
},
}
--==============================================================================
-- 4 · INTEGRATIONS
--==============================================================================
-- ── Agency HUD ───────────────────────────────────────────────────────────────
AgencyConfig.UseAgencyHUD = true -- enable the Agency-HUD hooks
AgencyConfig.SyncAgencyHUD = true -- share the phone open/close state with Agency-HUD
-- ── Notifications ────────────────────────────────────────────────────────────
-- Agency-Notify (free): https://agency-script.tebex.io/package/6937769
AgencyConfig.UseAgencyNotify = true
AgencyConfig.NotifyDuration = 5000 -- ms
-- ── Agency Reports (Reports app) ─────────────────────────────────────────────
-- Agency Reports (free): https://agency-script.tebex.io/package/6959744
AgencyConfig.UseAgencyReports = true
AgencyConfig.AgencyReportsProvider = 'v2' -- 'v2' | 'v2_ad_free' | 'legacy' | 'auto'
AgencyConfig.AgencyReportsCommand = 'areport'
-- ── Agency LifeInvader V2 ────────────────────────────────────────────────────
-- true = the Life Invader app opens Agency-LifeInvaderV2 instead of the built-in app.
AgencyConfig.EnableLifeInvaderV2Integration = false
-- ── Companion App (Settings > Companion App) ─────────────────────────────────
-- Pair the phone with the Agency Phone iOS app via QR code. No setup needed:
-- the server connects outbound to the Agency relay (no port forwarding).
AgencyConfig.Companion = {
Enable = true, -- show the Companion page and allow pairing
EnableRemote = true, -- paired devices may use the phone remotely
RelayUrl = 'https://api.agencyg.de', -- do not change unless instructed
TokenTTL = 300, -- seconds a pairing QR code stays valid
-- Only for servers on the same network as the relay. Leave empty.
RelayInternalUrl = '',
}
--==============================================================================
-- 5 · CALLS & VOICE
--==============================================================================
-- ── Calls ────────────────────────────────────────────────────────────────────
AgencyConfig.CallTimeout = 30 -- seconds until an unanswered call ends
AgencyConfig.CallRingInterval = 4000 -- ms between two rings
AgencyConfig.CallMaxRings = 10
-- ── Dialer ───────────────────────────────────────────────────────────────────
AgencyConfig.EnableDeathEmergency = true -- show the emergency overlay when the player dies
AgencyConfig.DialerEmergencyNumber = '911'
AgencyConfig.DialerTestNumber = '511' -- always-answered test line ('' = off)
AgencyConfig.DialerShowRecents = true
AgencyConfig.DialerMaxRecents = 20
-- ── Voice system ─────────────────────────────────────────────────────────────
-- 'auto' (recommended) | 'pma-voice' | 'saltychat' | 'mumble-voip' | 'tokovoip'
AgencyConfig.VoiceSystem = 'auto'
-- ── Walkie-talkie (Radio app) ────────────────────────────────────────────────
-- Channels only some jobs may join.
-- 'auto' = take them from qb-radio / ps-radio (RestrictedChannels, MaxFrequency)
-- table = set them here, e.g. { [1] = { police = true, ambulance = true } }
-- false = no locks
AgencyConfig.RadioChannelLocks = 'auto'
AgencyConfig.RadioLockDecimals = true -- a lock on 1 also covers 1.1 - 1.9
-- ── Payphones ────────────────────────────────────────────────────────────────
-- Street phone boxes: dial any number without a phone or carrier contract.
-- The person called sees the booth, not the caller.
AgencyConfig.Payphones = {
Enabled = true, -- false removes the payphones completely
Price = 5, -- charged when the call is answered (0 = free)
EmergencyCalls = true, -- dispatch numbers are free and alert police/EMS with the location
Account = 'cash', -- 'cash' | 'bank'
Currency = '$', -- shown on the keypad
MaxCallSeconds = 300, -- the line drops after this (0 = no limit)
CallerName = 'Payphone', -- name the person called sees
ShowBoothNumber = true, -- false = "Hidden Number"
NumberPrefix = '0800', -- booth number = prefix + 4 digits from its position
Interaction = 'auto', -- 'auto' = ox_target > qb-target > key | 'key' = always the key
Label = 'Use payphone', -- target option / key prompt
Key = 38, -- control for keypad and hang up (38 = E)
KeyLabel = 'E', -- key shown on the call card
Distance = 1.6, -- how close you must stand
WalkAwayDistance = 3.0, -- the call ends beyond this distance
Models = { -- every phone box model on the map
'prop_phonebox_01a', 'prop_phonebox_01b', 'prop_phonebox_01c',
'prop_phonebox_02', 'prop_phonebox_03', 'prop_phonebox_04',
'p_phonebox_01b_s', 'p_phonebox_02_s',
'sf_prop_sf_phonebox_01b_s', 'sf_prop_sf_phonebox_01b_straight',
},
}
-- ── Video calls & live streams (FaceZoom, Pictogram Live) ────────────────────
-- Runs over Cloudflare TURN. The API token stays on the server.
-- Sign up: https://dash.cloudflare.com/sign-up/realtime/turn
-- Create app: https://dash.cloudflare.com/?to=/:account/realtime/turn
AgencyConfig.StreamTransport = 'cloudflare-turn'
AgencyConfig.CloudflareTurnEnabled = true
-- Name, Token ID and API token of your TURN app: config_server.lua (Keys).
AgencyConfig.CloudflareTurnApiUrl = 'https://rtc.live.cloudflare.com/v1/turn/keys/%s/credentials/generate-ice-servers'
AgencyConfig.CloudflareTurnCredentialTTL = 43200 -- seconds
--==============================================================================
-- 6 · EMERGENCY
--==============================================================================
AgencyConfig.EnableMDT = true -- false disables the MDT for police and EMS
-- ── Dispatch ─────────────────────────────────────────────────────────────────
-- Where emergency calls and messages go:
-- 'internal' (built-in) | 'cd_dispatch' | 'ps-dispatch' | 'qs-dispatch'
-- 'core_dispatch' | 'custom' (fires agency-phone:dispatch:custom)
AgencyConfig.DispatchSystem = 'internal'
AgencyConfig.DispatchCodes = {
['911'] = { type = 'emergency', priority = 'high', label = 'Emergency Call', departments = {'police', 'ems'} },
['110'] = { type = 'police', priority = 'high', label = 'Police Emergency', departments = {'police'} },
['112'] = { type = 'ems', priority = 'high', label = 'Medical Emergency', departments = {'ems'} },
}
AgencyConfig.DispatchTimeout = 300 -- seconds a dispatch stays active (0 = until cleared)
AgencyConfig.DispatchSaveHistory = true -- keep the history in the database
--==============================================================================
-- 7 · NETWORK (eSIM carriers)
--==============================================================================
-- Without a paid plan the phone has no signal: no calls, messages or downloads.
AgencyConfig.CarrierBilling = {
Enabled = true, -- false = the plan is paid once, never again
IntervalMinutes = 1440, -- real minutes between two charges (1440 = daily)
BankReason = 'phone-carrier', -- text on the bank statement
}
-- speed : 1-5, affects downloads, message delay, mail and posting
-- calls : 'unlimited' or calls per restart
-- messages : 'unlimited' or messages per restart
-- price : charged from the bank when taken, then every billing interval
AgencyConfig.CarrierPlans = {
{
id = 'fleeca_mobile',
name = 'Fleeca Mobile',
icon = 'fa-solid fa-signal',
color = '#34c759',
speed = 2,
calls = 50,
messages = 100,
price = 30,
},
{
id = 'maze_telecom',
name = 'Maze Telecom',
icon = 'fa-solid fa-tower-cell',
color = '#007aff',
speed = 3,
calls = 'unlimited',
messages = 200,
price = 50,
},
{
id = 'lifeinvader_net',
name = 'LifeInvader Net',
icon = 'fa-solid fa-wifi',
color = '#5856d6',
speed = 4,
calls = 'unlimited',
messages = 'unlimited',
price = 80,
},
{
id = 'lossantos_5g',
name = 'LS 5G Ultra',
icon = 'fa-solid fa-bolt',
color = '#ff9500',
speed = 5,
calls = 'unlimited',
messages = 'unlimited',
price = 120,
},
}
--==============================================================================
-- 8 · SECURITY
--==============================================================================
AgencyConfig.FaceIdDefault = false -- Face Unlock on for new players
AgencyConfig.FaceIdAnimDuration = 2600 -- ms
AgencyConfig.LockScreenEnabled = true
--==============================================================================
-- 9 · CAMERA & MEDIA
--==============================================================================
-- ── Media storage ────────────────────────────────────────────────────────────
-- Where photos, clips, screen captures and voice messages are stored.
-- 'local' = on your own server, inside your database (oxmysql).
-- Works right after install: no account, no API key. (default)
-- 'cloudflare' = Cloudflare R2, free up to 10 GB. Faster for big servers.
-- Put your keys in config_server.lua (never in this file,
-- config.lua is sent to every player).
-- Step by step guide: https://docs.agencyg.de/phone/media-storage
AgencyConfig.MediaStorage = {
Provider = 'local', -- 'local' or 'cloudflare'
MaxFileMegabytes = 10, -- largest single file (clips, recordings)
TransferKilobytesPerSecond = 1000, -- 'local': how fast files are sent to players,
-- shared politely with the game connection.
-- Uploads from players are capped by FiveM itself
-- (about 165 KB/s): a photo takes ~1 s, a 15 s clip ~20 s.
Local = {
RetentionDays = 30, -- delete files older than this (0 = keep forever)
MaxStorageGigabytes = 10, -- delete the oldest files above this (0 = no limit)
},
}
-- ── Camera & gallery ─────────────────────────────────────────────────────────
AgencyConfig.CameraMaxPhotos = 50 -- photos in the camera roll
AgencyConfig.CameraQuality = 0.85 -- JPEG quality (0-1)
AgencyConfig.GalleryMaxPhotos = 50 -- photos per player
AgencyConfig.GalleryColumnsCount = 3 -- grid columns (2, 3 or 4)
-- ── Camera video (clips) ─────────────────────────────────────────────────────
-- Short clips through the viewfinder, stored in the gallery.
AgencyConfig.CameraVideo = {
Enabled = true, -- false hides the VIDEO mode
MaxDurationSeconds = 15, -- hard stop per clip (3-60)
Fps = 60,
Width = 480, -- px, the height follows the viewfinder
BitrateKbps = 2000, -- higher = sharper, bigger upload
MaxVideos = 20, -- clips per player (separate from photos)
CooldownSeconds = 3, -- spam guard between two clips
PoseClip = '', -- pose while filming ('' = first one the game ships)
MaxUploadMegabytes = 6, -- bigger clips are rejected
}
-- ── Screen capture (Control Centre) ──────────────────────────────────────────
-- Screenshots and recordings of the phone screen, saved to the gallery.
-- Recordings count against CameraVideo.MaxVideos.
AgencyConfig.ScreenCapture = {
Enabled = true, -- false turns off both
Screenshots = true,
ScreenshotWidth = 1116, -- px (372-1860)
Video = true,
MaxDurationSeconds = 30, -- hard stop per recording (5-300)
Fps = 20, -- max frame rate (5-30)
Width = 540, -- px (240-1080)
BitrateKbps = 1800,
MaxUploadMegabytes = 10, -- also capped by MediaStorage.MaxFileMegabytes
}
-- ── Voice messages & Recorder ────────────────────────────────────────────────
AgencyConfig.VoiceMessages = {
Enabled = true,
MaxSeconds = 60, -- a voice message sends itself at this length
}
AgencyConfig.Recorder = {
MaxSeconds = 300, -- longest recording
MaxRecordings = 50, -- kept per character
CloudSync = true, -- also save to AgencyCloud (player can switch it off)
}
-- ── AgencyCloud ──────────────────────────────────────────────────────────────
-- Cloud storage for photos and documents. Personal for every player,
-- Company per job. StorageTiers are the upgrades players can buy.
AgencyConfig.AgencyCloud = {
Enabled = true,
GalleryAutoSyncDefault = false,
Personal = {
Label = 'Personal Cloud',
BaseStorageMB = 200,
BaseAssetLimit = 50,
PurchaseStorageMB = 250,
PurchaseAssetCount = 25,
PurchasePrice = 5000,
MaxStorageMB = 5000,
MaxAssetLimit = 1000,
GallerySavePrice = 150,
DocumentSavePrice = 60,
AllowGalleryAssets = true,
AllowDocuments = true,
StorageTiers = {
{ id = 'plus', label = 'Plus', storageMb = 250, assetCount = 25, price = 5000 },
{ id = 'pro', label = 'Pro', storageMb = 750, assetCount = 75, price = 12000 },
{ id = 'vault', label = 'Vault', storageMb = 1500, assetCount = 160, price = 22000 },
},
},
Company = {
Label = 'Company Cloud',
BossOnly = true,
BaseStorageMB = 1000,
BaseAssetLimit = 150,
PurchaseStorageMB = 1000,
PurchaseAssetCount = 100,
PurchasePrice = 25000,
MaxStorageMB = 20000,
MaxAssetLimit = 5000,
GallerySavePrice = 350,
DocumentSavePrice = 180,
AllowGalleryAssets = true,
AllowDocuments = true,
StorageTiers = {
{ id = 'team', label = 'Team', storageMb = 1000, assetCount = 100, price = 25000 },
{ id = 'division', label = 'Division', storageMb = 2500, assetCount = 280, price = 52000 },
{ id = 'enterprise', label = 'Enterprise', storageMb = 5000, assetCount = 650, price = 95000 },
},
},
DefaultGalleryStorageBytes = 2000000, -- size counted per photo
DefaultVideoStorageBytes = 8000000, -- size counted per clip
DefaultDocumentStorageBytes = 102400, -- size counted per document
}
--==============================================================================
-- 10 · COMMUNICATION
--==============================================================================
-- ── Buzz (messages) ──────────────────────────────────────────────────────────
AgencyConfig.BuzzMaxMessages = 50 -- messages loaded per chat
AgencyConfig.BuzzAllowDelete = true
AgencyConfig.BuzzShowTimestamps = true
-- ── Contacts ─────────────────────────────────────────────────────────────────
AgencyConfig.ContactsMaxCount = 100 -- per player
AgencyConfig.ContactsAllowShare = true
AgencyConfig.ContactsDefaultSort = 'name' -- 'name' | 'recent'
-- ── Mail ─────────────────────────────────────────────────────────────────────
AgencyConfig.PostboxLoadHours = 72 -- how far back mails are loaded
AgencyConfig.PostboxMaxMails = 50
AgencyConfig.PostboxAllowDelete = true
AgencyConfig.PostboxMaxAccounts = 5 -- mail addresses per player
AgencyConfig.PostboxDefaultDomain = 'agencyg.de' -- players choose the part before the @
-- ── Pulse & Bleeter (social feeds) ───────────────────────────────────────────
AgencyConfig.PulseLoadHours = 12 -- how far back posts are loaded
AgencyConfig.PulseMaxLength = 280 -- characters per post
AgencyConfig.PulseAllowDelete = true -- delete own posts
AgencyConfig.PulseRefreshInterval = 30 -- auto refresh in seconds (0 = off)
AgencyConfig.BleeterMaxLength = 280 -- characters per bleet
-- ── Snapr ────────────────────────────────────────────────────────────────────
AgencyConfig.Snapr = {
-- How long a snap is shown; the sender picks within this range.
MinDurationSeconds = 1,
MaxDurationSeconds = 10,
DefaultDurationSeconds = 5,
KeepOpenedMinutes = 5, -- a seen snap is removed after this
ExpireUnopenedHours = 48, -- an unopened snap expires after this
MaxRecipients = 12, -- recipients per snap
-- Text chat in a conversation. Read chats are kept ChatKeepHours.
ChatEnabled = true,
ChatMaxLength = 300,
ChatKeepHours = 24,
-- Stickers drawn into the picture: location and phone time.
LocationSticker = true,
TimeSticker = true,
}
--==============================================================================
-- 11 · MUSIC & RADIO
--==============================================================================
-- ── Music library ────────────────────────────────────────────────────────────
-- The library starts empty. Players submit links (Submit tab), music admins
-- approve them (Review tab), then everyone can play them.
-- Make an admin: musicadmin <serverId> (console or ace 'command.musicadmin')
-- Always admin: ace 'agency.musicadmin'
-- Allowed: https links ending in .mp3 .ogg .oga .wav .m4a .aac .flac .opus
AgencyConfig.MusicAutoApprove = false -- true = skip the review
AgencyConfig.MusicMaxOpenSubmissions = 5 -- pending submissions per player
-- Own hosts that serve audio without a file extension, e.g. { 'cdn.myserver.com' }
AgencyConfig.MusicAllowedHosts = {
}
AgencyConfig.MusicSyncRadius = 30.0 -- meters in which others hear your music
AgencyConfig.MusicMaxVolume = 0.5 -- 0.0 - 1.0
-- Also accept links to external media sites. You are responsible for the
-- rights to that content on your server.
AgencyConfig.MusicAllowExternalLinks = false
-- ── Music review on Discord ──────────────────────────────────────────────────
-- Every submission is posted to a Discord webhook. Its address is in
-- config_server.lua (Keys.MusicDiscordWebhook), '' there = off.
AgencyConfig.MusicDiscordMentionRoleId = '' -- role ID pinged per submission (optional)
-- Public address of your server incl. port, no trailing slash, e.g.
-- 'http://123.45.67.89:30120'. Adds one-time Approve / Reject links to the
-- Discord post. '' = admins review in the phone (Music > Review).
AgencyConfig.MusicReviewCallbackUrl =''
-- ── GTA radio (Music app > Radio tab) ────────────────────────────────────────
-- Plays the original GTA V stations; keeps playing with the phone put away.
AgencyConfig.EnableRadioTab = true -- false hides the Radio tab
AgencyConfig.RadioKeepStationInVehicle = true -- take the station into a vehicle
AgencyConfig.RadioBlockWheelOnFoot = true -- block GTA's radio wheel on foot (vehicles stay vanilla)
-- id = internal GTA station name | name, genre, color = how the tile looks.
-- Reorder or remove freely. DLC stations need the DLC on the client.
AgencyConfig.RadioStations = {
{ id = 'RADIO_01_CLASS_ROCK', name = 'Los Santos Rock Radio', genre = 'Classic Rock', color = '#e2564a' },
{ id = 'RADIO_02_POP', name = 'Non-Stop-Pop FM', genre = 'Pop', color = '#ff4fa3' },
{ id = 'RADIO_03_HIPHOP_NEW', name = 'Radio Los Santos', genre = 'Modern Hip Hop', color = '#f5a623' },
{ id = 'RADIO_04_PUNK', name = 'Channel X', genre = 'Punk', color = '#8e8e93' },
{ id = 'RADIO_05_TALK_01', name = 'West Coast Talk Radio', genre = 'Talk', color = '#4a90d9' },
{ id = 'RADIO_06_COUNTRY', name = 'Rebel Radio', genre = 'Country', color = '#c08a4a' },
{ id = 'RADIO_07_DANCE_01', name = 'Soulwax FM', genre = 'Electronic', color = '#7b5cff' },
{ id = 'RADIO_08_MEXICAN', name = 'East Los FM', genre = 'Mexican', color = '#2fbf71' },
{ id = 'RADIO_09_HIPHOP_OLD', name = 'West Coast Classics', genre = 'Classic Hip Hop', color = '#d4a017' },
{ id = 'RADIO_11_TALK_02', name = 'Blaine County Radio', genre = 'Talk', color = '#6b8e5a' },
{ id = 'RADIO_12_REGGAE', name = 'The Blue Ark', genre = 'Reggae / Dub', color = '#3ec46d' },
{ id = 'RADIO_13_JAZZ', name = 'Worldwide FM', genre = 'Jazz / World', color = '#00b7c3' },
{ id = 'RADIO_14_DANCE_02', name = 'FlyLo FM', genre = 'Experimental', color = '#a855f7' },
{ id = 'RADIO_15_MOTOWN', name = 'The Lowdown 91.1', genre = 'Motown / Soul', color = '#b5651d' },
{ id = 'RADIO_16_SILVERLAKE', name = 'Radio Mirror Park', genre = 'Indie / Electro', color = '#5ac8fa' },
{ id = 'RADIO_17_FUNK', name = 'Space 103.2', genre = 'Funk', color = '#ff6b35' },
{ id = 'RADIO_18_90S_ROCK', name = 'Vinewood Boulevard Radio', genre = 'Alternative Rock', color = '#e0457b' },
{ id = 'RADIO_20_THELAB', name = 'The Lab', genre = 'Original Score', color = '#00d4ff' },
{ id = 'RADIO_21_DLC_XM17', name = 'Blonded Los Santos 97.8', genre = 'R&B / Hip Hop', color = '#f0c419' },
{ id = 'RADIO_22_DLC_BATTLE_MIX1_RADIO', name = 'LS Underground Radio', genre = 'House / Techno', color = '#9b59b6' },
{ id = 'RADIO_23_DLC_XM19_RADIO', name = 'iFruit Radio', genre = 'Hip Hop / Grime', color = '#31c48d' },
{ id = 'RADIO_27_DLC_PRHEI4', name = 'Still Slipping Los Santos', genre = 'Downtempo', color = '#ff8a5b' },
{ id = 'RADIO_34_DLC_HEI4_KULT', name = 'Kult FM', genre = 'Post-Punk / New Wave',color = '#6c7a89' },
{ id = 'RADIO_35_DLC_HEI4_MLR', name = 'The Music Locker', genre = 'House', color = '#e84393' },
{ id = 'RADIO_37_MOTOMAMI', name = 'MOTOMAMI Los Santos', genre = 'Latin / Reggaeton', color = '#ff3b6b' },
}
--==============================================================================
-- 12 · FINANCE
--==============================================================================
-- ── Wallet ───────────────────────────────────────────────────────────────────
AgencyConfig.WalletMinTransfer = 1
AgencyConfig.WalletMaxTransfer = 1000000
AgencyConfig.WalletShowHistory = false -- transaction history (planned)
AgencyConfig.WalletCurrency = '$'
-- Fixed-term deposits. interest = % paid at the end of the term.
AgencyConfig.WalletFixedTerms = {
{ id = 'fd_7', label = '7 Days', days = 7, interest = 2.0 },
{ id = 'fd_14', label = '14 Days', days = 14, interest = 3.0 },
{ id = 'fd_30', label = '30 Days', days = 30, interest = 5.0 },
}
-- ── Agency Pay terminals ─────────────────────────────────────────────────────
-- Payment points in the world, paid with the Wallet.
-- coords : x, y, z, w (heading, optional)
-- amount : price charged from the bank
-- reward : item handed out after a successful payment (optional)
AgencyConfig.AgencyPayTerminals = {
{
id = 'agency_water_terminal_1',
coords = { x = 27.5543, y = -1343.0767, z = 29.4970, w = 0.6853 },
radius = 2.6,
merchant = 'Agency Water Terminal',
title = 'Agency Pay',
subtitle = 'Tap to buy a bottle of water',
label = 'Water Bottle',
amount = 1.00,
currency = '$',
icon = 'fa-solid fa-bottle-water',
accent = '#5ac8fa',
manualConfirm = true,
autoStart = false,
showMarker = true,
markerDistance = 18.0,
textDistance = 6.0,
markerType = 1,
markerScale = 0.34,
markerColor = { r = 90, g = 200, b = 250, a = 185 },
markerBob = true,
showBlip = false,
metadata = {
terminalId = 'agency_water_terminal_1',
rewardLabel = 'Water',
},
reward = {
item = 'water',
amount = 1,
},
serverEvent = 'agency-phone:server:handleAgencyPayTerminalPurchase',
},
}
-- ── Crypto ───────────────────────────────────────────────────────────────────
-- basePrice : starting price in $
-- volatility : typical move per hour (0.05 = about 5 %)
-- realCrypto : real coin it is modelled on (display only)
AgencyConfig.CryptoMarkets = {
{
id = 'digicoin',
name = 'DigiCoin',
symbol = 'DGC',
icon = '₿',
color = '#f7931a',
basePrice = 45000,
volatility = 0.05,
realCrypto = 'Bitcoin'
},
{
id = 'etherchain',
name = 'EtherChain',
symbol = 'ETC',
icon = '⟠',
color = '#627eea',
basePrice = 2800,
volatility = 0.08,
realCrypto = 'Ethereum'
},
{
id = 'litemark',
name = 'LiteMark',
symbol = 'LTM',
icon = 'Ł',
color = '#345d9d',
basePrice = 150,
volatility = 0.12,
realCrypto = 'Litecoin'
},
{
id = 'ripplenet',
name = 'RippleNet',
symbol = 'RPN',
icon = '✕',
color = '#00aae4',
basePrice = 0.85,
volatility = 0.15,
realCrypto = 'XRP'
},
{
id = 'cardania',
name = 'Cardania',
symbol = 'CDA',
icon = '₳',
color = '#0033ad',
basePrice = 1.25,
volatility = 0.13,
realCrypto = 'Cardano'
}
}
AgencyConfig.CryptoUpdateInterval = 10000 -- ms between price updates (also used for stocks)
AgencyConfig.CryptoTradeAmount = 0.1 -- default amount per trade
-- ── Stocks ───────────────────────────────────────────────────────────────────
-- Same fields as crypto; icon is a Font Awesome class. All prices and trades
-- run on the server. Do not rename an id, players would lose their holdings.
AgencyConfig.StockMarkets = {
{ id = 'lifeinvader', name = 'LifeInvader', symbol = 'LFI', color = '#5ac8fa', icon = 'fa-solid fa-share-nodes', basePrice = 125, volatility = 0.08 },
{ id = 'redwood', name = 'Redwood Cigarettes', symbol = 'RWC', color = '#ff3b30', icon = 'fa-solid fa-smoking', basePrice = 85, volatility = 0.12 },
{ id = 'burger', name = 'Burger Shot', symbol = 'BRG', color = '#ff9500', icon = 'fa-solid fa-burger', basePrice = 45, volatility = 0.15 },
{ id = 'ecola', name = 'eCola', symbol = 'ECL', color = '#34c759', icon = 'fa-solid fa-bottle-water', basePrice = 65, volatility = 0.10 },
{ id = 'mazebank', name = 'Maze Bank', symbol = 'MZB', color = '#007aff', icon = 'fa-solid fa-building-columns', basePrice = 180, volatility = 0.06 },
{ id = 'ammu', name = 'Ammu-Nation', symbol = 'AMU', color = '#5856d6', icon = 'fa-solid fa-crosshairs', basePrice = 95, volatility = 0.14 },
{ id = 'cluckin', name = 'Cluckin Bell', symbol = 'CLK', color = '#ffcc00', icon = 'fa-solid fa-drumstick-bite', basePrice = 52, volatility = 0.11 },
{ id = 'postopto', name = 'Post OP', symbol = 'POP', color = '#af52de', icon = 'fa-solid fa-truck', basePrice = 38, volatility = 0.16 },
{ id = 'gruppe6', name = 'Gruppe Sechs', symbol = 'GRP', color = '#00c7be', icon = 'fa-solid fa-shield-halved', basePrice = 142, volatility = 0.07 },
{ id = 'vangelico', name = 'Vangelico', symbol = 'VGL', color = '#ffd60a', icon = 'fa-solid fa-gem', basePrice = 210, volatility = 0.09 },
{ id = 'flyus', name = 'FlyUS', symbol = 'FLY', color = '#64d2ff', icon = 'fa-solid fa-plane', basePrice = 72, volatility = 0.11 },
{ id = 'marketcore', name = 'Agency Market Core ETF', symbol = 'AMC', color = '#8e8e93', icon = 'fa-solid fa-chart-pie', basePrice = 100, volatility = 0.035, etf = true },
{ id = 'stabilityplus', name = 'Stability Plus ETF', symbol = 'SPL', color = '#30d158', icon = 'fa-solid fa-scale-balanced', basePrice = 100, volatility = 0.025, etf = true },
}
-- Trading hours in game time (crypto trades around the clock). false = always open.
AgencyConfig.StockMarketHours = { open = 9, close = 17 }
-- ── Gambling apps ────────────────────────────────────────────────────────────
AgencyConfig.EnableMoneyGames = true -- master switch, false hides all four games
-- Single games. false removes the game from phone and store; the server
-- refuses its bets.
AgencyConfig.MoneyGameApps = {
dice = true,
coinflip = true,
slots = true,
roulette = true,
}
-- Highest win as a multiple of the stake, enforced on the server.
AgencyConfig.MoneyGameMaxMultiplier = {
dice = 5, -- 5x on a 12
coinflip = 2,
slots = 12, -- 12x on three diamonds
roulette = 36, -- 36x on green
}
--==============================================================================
-- 13 · DARKNET
--==============================================================================
-- A market paid in crypto. Players order, wait while the package is prepared,
-- then collect it at a dead drop only they know. Prices are in $ and paid at
-- the live coin price. Items your inventory does not know are skipped.
--
-- UseBlackmarket: 'auto' = use Agency-Blackmarket's market when it runs,
-- false = always the items below.
AgencyConfig.Darknet = {
Enabled = true,
UseBlackmarket = 'auto',
Coin = 'digicoin', -- crypto id from AgencyConfig.CryptoMarkets
Prep = { 4, 9 }, -- minutes until the package is ready (min, max)
Expire = 45, -- minutes a drop waits before it goes cold
Refund = 50, -- % of the coins refunded when it does
MaxPieces = 5, -- pieces per order
AlertChance = 25, -- % chance of an anonymous police tip on pickup
AlertJobs = { 'police' },
PickupPrompt = 'Take the package',
RepPerPickup = { per = 500, min = 2 }, -- 1 point per $500 ordered, at least 2
-- rep: reputation needed | discount: % off | orders: open orders at once
Levels = {
{ name = 'Ghost', rep = 0, discount = 0, orders = 1 },
{ name = 'Runner', rep = 40, discount = 3, orders = 1 },
{ name = 'Broker', rep = 120, discount = 6, orders = 2 },
{ name = 'Insider', rep = 280, discount = 10, orders = 2 },
{ name = 'Phantom', rep = 500, discount = 15, orders = 3 },
},
-- category : tools | tech | gear (others are shown as written)
-- stock : pieces available | restock: minutes per piece back
-- level : level needed | amount : pieces handed over per piece ordered
Items = {
{ id = 'lockpick', item = 'advancedlockpick', label = 'Advanced Lockpick', desc = 'Opens what the cheap ones cannot.', category = 'tools', price = 400, stock = 12, restock = 20, level = 1 },
{ id = 'screwdriver', item = 'screwdriverset', label = 'Screwdriver Set', desc = 'Quiet tools for loud problems.', category = 'tools', price = 250, stock = 10, restock = 15, level = 1 },
{ id = 'radio', item = 'radio', label = 'Encrypted Radio', desc = 'Frequency hopping. No serial number.', category = 'tech', price = 800, stock = 6, restock = 30, level = 1 },
{ id = 'electronickit', item = 'electronickit', label = 'Electronic Kit', desc = 'For locks that think.', category = 'tech', price = 1200, stock = 6, restock = 30, level = 2 },
{ id = 'armor', item = 'armor', label = 'Kevlar Vest', desc = 'Level III. Serial numbers filed off.', category = 'gear', price = 1500, stock = 5, restock = 40, level = 2 },
{ id = 'trojan', item = 'trojan_usb', label = 'Trojan USB', desc = 'Plug it in, walk away.', category = 'tech', price = 2500, stock = 4, restock = 45, level = 3 },
{ id = 'drill', item = 'drill', label = 'Heavy Drill', desc = 'Gets through the door, not quietly.', category = 'tools', price = 3500, stock = 3, restock = 60, level = 3 },
{ id = 'thermite', item = 'thermite', label = 'Thermite', desc = 'Handle with gloves.', category = 'tools', price = 5000, stock = 3, restock = 60, level = 4 },
{ id = 'laptop', item = 'laptop', label = 'Hacking Laptop', desc = 'Pre-loaded. Never online twice.', category = 'tech', price = 7500, stock = 2, restock = 90, level = 5 },
},
Drops = {}, -- dead drops; empty = DarknetPickupLocations below
}
-- Dead drop locations. One is picked at random per order and marked on the GPS.
AgencyConfig.DarknetPickupLocations = {
{ x = 126.42, y = -1282.71, z = 29.27, label = 'Strawberry Alley' },
{ x = -587.53, y = -1064.37, z = 22.34, label = 'La Mesa Backstreet' },
{ x = 373.24, y = -826.52, z = 29.30, label = 'Mission Row Dumpster' },
{ x = -1205.42, y = -906.28, z = 12.33, label = 'Vespucci Canal' },
{ x = 1137.86, y = -982.34, z = 46.42, label = 'Murrieta Heights' },
{ x = -46.83, y = -1758.64, z = 29.42, label = 'Davis Industrial' },
}
--==============================================================================
-- 14 · VEHICLES & RIDES
--==============================================================================
-- ── Garage ───────────────────────────────────────────────────────────────────
-- 'auto' tries: okokGarage, cd_garage, md-garage, qb-garages, qbx_garages,
-- jg-advancedgarages, qs-advancedgarages, renewed-garage, loaf_garage,
-- then the database. Or set one of those names to force it.
AgencyConfig.GarageSystem = 'auto'
AgencyConfig.GarageSpawnCost = 200 -- $ per vehicle request
AgencyConfig.GarageMaxSpawned = 3 -- vehicles out at once per player
AgencyConfig.GarageCooldown = 120 -- seconds between requests (0 = off)
-- ── AutoRide (driverless pickup) ─────────────────────────────────────────────
AgencyConfig.EnableAutoRideApp = true -- AutoRide app available
AgencyConfig.EnableAutoRideViaAngy = true -- Angy can order a ride (independent of the app)
AgencyConfig.AutoRideVehicleModel = 'stretch' -- default model
-- Vehicles to choose from, in this order; the first one is preselected.
-- image is optional (path relative to html/), otherwise a class icon is shown.
AgencyConfig.AutoRideVehicleOptions = {
{ model = 'zero', label = 'Agency Zero', image = 'img/ar_zero.png' },
{ model = 'stretch', label = 'Agency Limo', image = 'img/ar_stretch.svg' },
{ model = 'neon', label = 'Agency E-Sport 4S', image = 'img/ar_neon.svg' },
{ model = 'raiden', label = 'Agency Executive EV', image = 'img/ar_raiden.svg' },
}
-- Models without a steering wheel: board the front first, doors open by themselves.
AgencyConfig.AutoRideFrontEntryModels = { 'zero' }
AgencyConfig.AutoRideCruiseSpeed = 22.0 -- speed during the ride
AgencyConfig.AutoRidePickupSpeed = 34.0 -- speed while coming to the player
AgencyConfig.AutoRideArrivalRadius = 18.0
AgencyConfig.AutoRideDropoffRadius = 22.0
AgencyConfig.AutoRideBoardingRadius = 12.0 -- distance to press E and get in
AgencyConfig.AutoRideUseInvisibleDriver = true
AgencyConfig.AutoRideIgnoreTrafficToPickup = true -- ignore traffic rules on the way to the player
AgencyConfig.AutoRideBaseFare = 500 -- $ charged when ordering
AgencyConfig.AutoRideCostPerKm = 100 -- $ per started kilometer
--==============================================================================
-- 15 · JOBS & SERVICES
--==============================================================================
-- ── Job apps ─────────────────────────────────────────────────────────────────
-- Which framework jobs can see and download each job app.
AgencyConfig.JobApps = {
police = {
appId = 'police_mdt',
jobNames = {'police', 'pd', 'lspd', 'bcso', 'sheriff'},
},
ems = {
appId = 'ems_mdt',
jobNames = {'ambulance', 'ems', 'doctor', 'medic', 'fire'},
},
mechanic = {
appId = 'mechanic_app',
jobNames = {'mechanic', 'bennys', 'lscustoms', 'tuner'},
},
}
-- ── Jobs app listings ────────────────────────────────────────────────────────
-- Offers in the Jobs app. x / y = map position, phone = contact number.
AgencyConfig.EmploymentListings = {
{
id = 'ls-logistics',
title = 'Delivery Driver',
company = 'Los Santos Logistics',
location = 'Mission Row, Los Santos',
salary = '$3,200 / week',
type = 'Full-Time',
description = 'Deliver packages across the city with route bonuses and clean-driver rewards.',
color = '#34c759',
x = 121.4,
y = -3031.9,
phone = '310-555-0181',
},
{
id = 'dockyard-security',
title = 'Night Security',
company = 'Port Security Group',
location = 'Elysian Island',
salary = '$2,850 / week',
type = 'Shift',
description = 'Patrol restricted zones, report incidents, and coordinate with dispatch.',
color = '#5ac8fa',
x = -225.1,
y = -2684.3,
phone = '310-555-0172',
},
{
id = 'vinewood-cafe',
title = 'Barista',
company = 'Bean Machine',
location = 'Vinewood',
salary = '$2,100 / week',
type = 'Part-Time',
description = 'Prepare drinks, handle front desk orders, and keep service flowing during rush hours.',
color = '#ff9f0a',
x = -634.9,
y = 236.1,
phone = '310-555-0122',
},
{
id = 'city-maintenance',
title = 'Street Maintenance',
company = 'City Works',
location = 'La Mesa',
salary = '$3,000 / week',
type = 'Contract',
description = 'Repair public infrastructure and assist with emergency city maintenance tasks.',
color = '#af52de',
x = 727.7,
y = -1079.7,
phone = '310-555-0196',
},
}
-- ── Agency Eats (delivery job) ───────────────────────────────────────────────
-- Restaurants where drivers pick up orders.
AgencyConfig.EatsRestaurants = {
{ name = 'Burger Shot', x = -1196.42, y = -891.35, z = 14.0 },
{ name = "Cluckin' Bell", x = -72.68, y = 6253.11, z = 31.09 },
{ name = 'Pizza This', x = 540.66, y = 101.25, z = 96.44 },
{ name = 'Bean Machine', x = -628.16, y = 236.60, z = 81.97 },
{ name = 'Up-n-Atom', x = 89.95, y = 289.42, z = 110.21 },
{ name = 'Taco Bomb', x = 12.04, y = -1605.57, z = 29.37 },
}
AgencyConfig.EatsPayPerKm = 20 -- $ per kilometer driven
AgencyConfig.EatsPayMin = 15 -- lowest pay per delivery
AgencyConfig.EatsPayMax = 200 -- highest pay per delivery
AgencyConfig.EatsPickupRadius = 15.0 -- meters to the restaurant for pickup
-- ── Maps quick navigation ────────────────────────────────────────────────────
-- Buttons in the Maps app that route to the nearest blip of these sprites.
AgencyConfig.MapFastNavEntries = {
{ id = 'gas', labelKey = 'maps_gas_station', icon = 'fa-gas-pump', color = '#0a84ff', sprites = { 361 } },
{ id = 'market', labelKey = 'maps_market', icon = 'fa-basket-shopping', color = '#ff9500', sprites = { 52, 77, 102 } },
{ id = 'atm', labelKey = 'maps_atm', icon = 'fa-credit-card', color = '#30d158', sprites = { 277 } },
{ id = 'clothing', labelKey = 'maps_clothing_store', icon = 'fa-shirt', color = '#bf5af2', sprites = { 73 } },
{ id = 'tattoo', labelKey = 'maps_tattoo_parlor', icon = 'fa-wand-magic-sparkles', color = '#ff9f0a', sprites = { 75 } },
{ id = 'barber', labelKey = 'maps_barber', icon = 'fa-scissors', color = '#5e72eb', sprites = { 71 } },
{ id = 'bar', labelKey = 'maps_bar', icon = 'fa-martini-glass-citrus', color = '#ff7a00', sprites = { 93 } },
}
--==============================================================================
-- 16 · ANGY
--==============================================================================
-- Angy is the phone's built-in assistant: open apps, call or text contacts,
-- order an AutoRide, set a waypoint, check balance and weather. It runs on
-- fixed rules inside the phone. No AI, no outside service, no key needed.
AgencyConfig.EnableAngy = true -- false removes the app and its key
--==============================================================================
-- 17 · LOGGING (Discord webhooks)
--==============================================================================
-- The webhook addresses are in config_server.lua (Webhooks), so players
-- never receive them.
--==============================================================================
-- 18 · APPS
--==============================================================================
-- ── App Store ────────────────────────────────────────────────────────────────
AgencyConfig.AppStoreEnabled = true
AgencyConfig.AppStorePersist = true -- remember installs in localStorage
-- ── Developer mode ───────────────────────────────────────────────────────────
-- Shows developer/example apps such as "Agency Demo". Keep false when live.
AgencyConfig.DeveloperMode = false
-- ── Protected apps ───────────────────────────────────────────────────────────
-- Can never be uninstalled and are always restored on load.
AgencyConfig.ProtectedApps = { 'appstore', 'settings', 'dialer', 'buzz', 'contacts', 'snap', 'gallery', 'clock', 'wallet', 'agencyai' }
-- ── Apps from other resources ────────────────────────────────────────────────
-- Home screen slot for apps added via exports['agency-phone']:RegisterApp.
-- 16 slots per page, counted from 0 (page 2 starts at 16).
AgencyConfig.ExternalAppSlots = {
topvsocial = 17, -- TopV Social (phone-topv), page 2 next to Weather
}
-- ── App list ─────────────────────────────────────────────────────────────────
-- id app id, do not change
-- label name on the home screen
-- icon Font Awesome class | image: optional picture instead
-- color icon colour | colorDark: colour in dark mode
-- slot home screen position
-- installed true = on the home screen, false = in the Store
-- enabled false = hidden completely
-- category Store category
-- requiresJob only for jobs from AgencyConfig.JobApps
-- requiresLogin app needs an account
-- storeDesc / features text on the Store page
-- Own apps go into the apps/ folder, see apps/README.md.
AgencyConfig.Apps = {
-- ═══════════════════════════════════════════════════════════
-- SYSTEM APPS
-- ═══════════════════════════════════════════════════════════
{
id = "dialer",
label = "Phone",
icon = "fa-solid fa-phone",
color = "#4cd964",
colorDark = "#34c759",
slot = 1,
installed = true,
enabled = true,
},
{
id = "buzz",
label = "Buzz",
icon = "fa-solid fa-comment",
color = "#34c759",
colorDark = "#28a745",
slot = 2,
installed = true,
enabled = true,
},
{
id = "contacts",
label = "Contacts",
icon = "fa-solid fa-user-group",
color = "#ff9500",
colorDark = "#e08600",
slot = 3,
installed = true,
enabled = true,
},
{
id = "snap",
label = "Camera",
icon = "fa-solid fa-camera",
color = "#8e8e93",
colorDark = "#636366",
slot = 4,
installed = true,
enabled = true,
},
{
id = "chirper",
label = "Pulse",
icon = "fa-solid fa-feather",
color = "#af52de",
colorDark = "#9b30d1",
slot = 35,
installed = false,
enabled = false,
},
{
id = "postbox",
label = "Mail",
icon = "fa-solid fa-envelope",
color = "#5ac8fa",
colorDark = "#32ade6",
slot = 6,
installed = true,
enabled = true,
},
{
id = "wallet",
label = "Wallet",
icon = "fa-solid fa-wallet",
color = "#007aff",
colorDark = "#0056cc",
slot = 7,
installed = true,
enabled = true,
},
{
id = "gallery",
label = "Photos",
icon = "fa-solid fa-images",
color = "#ff2d55",
colorDark = "#d6204a",
slot = 8,
installed = true,
enabled = true,
},
{
id = "report",
label = "Reports",
icon = "fa-solid fa-flag",
color = "#ff3b30",
colorDark = "#d63025",
slot = 9,
installed = true,
enabled = true,
},
{
id = "settings",
label = "Settings",
icon = "fa-solid fa-gear",
color = "#8e8e93",
colorDark = "#636366",
slot = 10,
installed = true,
enabled = true,
},
{
id = "agencyai",
label = "Angy",
icon = "fa-solid fa-wand-magic-sparkles",
image = "img/Agencylogo.png", -- the Agency mark on gold, like the Agency Watch
color = "#e2b649",
colorDark = "#a8801f",
slot = 11,
installed = true,
enabled = true,
},
{
id = "appstore",
label = "Store",
icon = "fa-solid fa-bag-shopping",
color = "#007aff",
colorDark = "#0056cc",
slot = 12,
installed = true,
enabled = true,
},
{
id = "agencycloud",
label = "AgencyCloud",
icon = "fa-solid fa-cloud",
color = "#4cc6ff",
colorDark = "#0a84ff",
category = "productivity",
slot = 13,
installed = true,
enabled = true,
storeDesc = "Your personal and company cloud storage. Sync files, photos, and documents across all your Agency devices.",
features = {"Personal & company storage", "Cross-device sync", "Photo gallery backup", "Document management", "Storage tier upgrades"},
},
-- ═══════════════════════════════════════════════════════════
-- PRODUCTIVITY & NAVIGATION
-- ═══════════════════════════════════════════════════════════
{
id = "calculator",
label = "Calculator",
icon = "fa-solid fa-calculator",
color = "#ff9500",
colorDark = "#e08600",
category = "productivity",
slot = 13,
installed = true,
enabled = true,
storeDesc = "A powerful calculator app for quick calculations on the go.",
features = {"Basic arithmetic operations", "Percentage calculations", "AgencyOS26.5-style interface", "Instant results"},
},
{
id = "clock",
label = "Clock",
icon = "fa-solid fa-clock",
color = "#000000",
colorDark = "#1c1c1e",
category = "productivity",
slot = 14,
installed = true,
enabled = true,
storeDesc = "Keep track of time with world clocks, alarms, stopwatch, and timers.",
features = {"World clock display", "Stopwatch with precision timing", "Multiple alarms", "Timer functionality"},
},
{
id = "notes",
label = "Notes",
icon = "fa-solid fa-note-sticky",
color = "#ffcc00",
colorDark = "#e6b800",
category = "productivity",
slot = 15,
installed = true,
enabled = true,
storeDesc = "Jot down ideas, tasks, and reminders instantly.",
features = {"Quick note creation", "Persistent storage", "Easy organization", "Simple interface"},
},
{
id = "calendar",
label = "Calendar",
icon = "fa-solid fa-calendar-days",
color = "#ff3b30",
colorDark = "#d70015",
category = "productivity",
slot = 14,
installed = true,
enabled = true,
storeDesc = "Plan your day: events with time, place and reminder, repeating dates and a home-screen widget for what comes next.",
features = {"Month view with event dots", "Reminders as notifications", "Repeating events", "Four colour-coded calendars", "Home-screen widget"},
},
{
id = "weather",
label = "Weather",
icon = "fa-solid fa-cloud-sun",
color = "#5ac8fa",
colorDark = "#32ade6",
category = "productivity",
slot = 16,
installed = true,
enabled = true,
storeDesc = "Stay informed about current weather conditions in Los Santos.",
features = {"Real-time weather display", "Temperature info", "Current conditions", "Location-based data"},
},
{
id = "compass",
label = "Compass",
icon = "fa-solid fa-compass",
color = "#ff3b30",
colorDark = "#d63025",
category = "navigation",
slot = 17,
installed = false,
enabled = true,
storeDesc = "Navigate the city with an accurate digital compass.",
features = {"Real-time heading direction", "Accurate navigation", "Always accessible", "Minimal interface"},
},
{
id = "radio",
label = "Radio",
-- fa-walkie-talkie is Font Awesome Pro only and would show an empty box.
icon = "fa-solid fa-tower-broadcast",
color = "#ff6b6b",
colorDark = "#d94848",
category = "utilities",
slot = 18,
installed = false,
enabled = true,
storeDesc = "Connect to various radio channels and communicate on the go.",
features = {"Multiple frequency channels", "Quick channel switching", "Clear audio", "Emergency frequencies"},
},
-- Flashlight lives in the Control Centre (swipe down top right).
{
id = "speedometer",
label = "Speedo",
icon = "fa-solid fa-gauge-high",
color = "#ff2d55",
colorDark = "#d6204a",
category = "navigation",
slot = 20,
installed = false,
enabled = true,
storeDesc = "Monitor your vehicle's speed with a digital speedometer.",
features = {"Real-time speed display", "Multiple unit options", "GPS speed tracking", "Always visible"},
},
{
id = "gps",
label = "Maps",
icon = "fa-solid fa-map-location-dot",
color = "#34c759",
colorDark = "#28a745",
category = "navigation",
slot = 21,
installed = false,
enabled = true,
storeDesc = "Navigate Los Santos with GPS waypoints and route planning.",
features = {"Set custom waypoints", "Route guidance", "Real-time navigation", "Location sharing"},
},
-- ═══════════════════════════════════════════════════════════
-- FINANCE, SERVICES & GAMES
-- ═══════════════════════════════════════════════════════════
{
id = "crypto",
label = "Crypto",
icon = "fa-brands fa-bitcoin",
color = "#f7931a",
colorDark = "#d97c0e",
slot = 22,
installed = false,
enabled = true,
storeDesc = "Buy, sell, and track cryptocurrency markets in real-time.",
features = {"Live market prices", "Portfolio tracking", "Trading functionality", "Transaction history"},
},
{
id = "stocks",
label = "Stocks",
icon = "fa-solid fa-chart-line",
color = "#007aff",
colorDark = "#0056cc",
slot = 33,
installed = false,
enabled = true,
storeDesc = "Trade stocks of Los Santos companies and build your portfolio.",
features = {"8 Los Santos companies", "Real-time price updates", "Buy/sell shares", "Portfolio tracking"},
category = "finance",
},
{
id = "dice",
label = "Dice Game",
category = "games",
icon = "fa-solid fa-dice",
color = "#ff2d55",
colorDark = "#d6204a",
slot = 23,
installed = false,
enabled = true,
storeDesc = "Roll dice against other players. Classic gambling game.",
features = {"1v1 dice duels", "Customizable bet amounts", "Roll history", "Fair random rolls"},
},
{
id = "darkweb",
label = "Darknet",
icon = "fa-solid fa-skull-crossbones",
color = "#1c1c1e",
colorDark = "#000000",
category = "darknet",
slot = 24,
installed = false,
enabled = true,
storeDesc = "Access the underground market. Anonymous and untraceable.",
features = {"Anonymous browsing", "Encrypted transactions", "Black market access", "High-risk items"},
},
{
id = "racing",
label = "Races",
icon = "fa-solid fa-flag-checkered",
color = "#ff9500",
colorDark = "#e08600",
category = "services",
slot = 25,
installed = false,
enabled = true,
storeDesc = "Compete in street races and track your best times.",
features = {"Create custom races", "Join active races", "Leaderboards", "Race statistics"},
},
{
id = "services",
label = "Services",
icon = "fa-solid fa-book-open",
color = "#ffd60a",
colorDark = "#d4a800",
category = "utilities",
slot = 27,
installed = false,
enabled = true,
storeDesc = "Request taxis, mechanics, and various city services.",
features = {"Taxi services", "Mechanic calls", "Emergency services", "Quick booking"},
},
{
id = "aipickup",
label = "AutoRide",
icon = "fa-solid fa-car-side",
color = "#00c7be",
colorDark = "#0a84ff",
category = "services",
slot = 26,
installed = true,
enabled = true,
storeDesc = "Driverless limousine pickup and autonomous dropoff service.",
features = {"Driverless 4-seat limousine", "Pickup at your location", "Set waypoint before or during ride", "Autonomous routing to destination"},
},
{
id = "food",
label = "AgencyEats",
icon = "fa-solid fa-burger",
color = "#ff3b30",
colorDark = "#d62020",
category = "services",
slot = 28,
installed = false,
enabled = true,
storeDesc = "Order food from local restaurants and get it delivered to your location.",
features = {"Browse menus", "Place orders", "Track delivery", "Restaurant ratings"},
},
{
id = "invoices",
label = "Invoices",
category = "finance",
icon = "fa-solid fa-file-invoice-dollar",
color = "#30d158",
colorDark = "#28b54c",
slot = 29,
installed = false,
enabled = true,
storeDesc = "Manage and pay your invoices and outstanding bills.",
features = {"View pending bills", "Pay invoices", "Transaction history", "Payment reminders"},
},
{
id = "employment",
label = "Jobs",
category = "utilities",
icon = "fa-solid fa-briefcase",
color = "#007aff",
colorDark = "#0056cc",
slot = 30,
installed = false,
enabled = true,
storeDesc = "Find employment opportunities and manage your career.",
features = {"Job listings", "Application tracking", "Career information", "Salary details"},
},
{
id = "garage",
label = "Garage",
category = "utilities",
icon = "fa-solid fa-warehouse",
color = "#5856d6",
colorDark = "#4240b0",
slot = 32,
installed = true,
enabled = true,
storeDesc = "Access and manage your stored vehicles and garage.",
features = {"Vehicle storage", "Quick spawn", "Vehicle information", "Garage locations"},
},
{
id = "coinflip",
label = "Coin Flip",
category = "games",
icon = "fa-solid fa-coins",
color = "#ffcc00",
colorDark = "#e6b800",
slot = 37,
installed = false,
enabled = true,
storeDesc = "Flip a coin and bet against other players. Heads or tails?",
features = {"Heads or tails betting", "Fair coin flip", "Bet against players", "Flip history"},
},
{
id = "slots",
label = "Lucky Slots",
category = "games",
icon = "fa-solid fa-clover",
color = "#34c759",
colorDark = "#28a745",
slot = 38,
installed = false,
enabled = true,
storeDesc = "Try your luck at the slot machine. Match symbols to win big!",
features = {"Classic slot machine", "Multiple symbol combos", "Win multipliers", "Jackpot system"},
},
{
id = "roulette",
label = "Roulette",
category = "games",
icon = "fa-solid fa-circle-dot",
color = "#ff3b30",
colorDark = "#d63025",
slot = 39,
installed = false,
enabled = true,
storeDesc = "Place your bets on the roulette wheel. Red, black, or green?",
features = {"Red/Black/Green bets", "Number betting", "Realistic wheel spin", "Payout system"},
},
-- ── Arcade games (no money involved) ──
{
id = "skyhopper",
label = "Sky Hopper",
icon = "fa-solid fa-dove",
color = "#4cd964",
colorDark = "#3bb54a",
slot = 40,
installed = false,
enabled = true,
category = "games",
storeDesc = "Tap to glide through the skyline, avoid the pipes and beat your best run.",
features = {"Classic gameplay", "High score tracking", "Smooth animations", "Addictive fun"},
},
{
id = "gametilemerge",
label = "Tile Merge",
icon = "fa-solid fa-border-all",
color = "#f59563",
colorDark = "#e07840",
slot = 41,
installed = false,
enabled = true,
category = "games",
storeDesc = "Slide numbered tiles to combine them and reach the highest score!",
features = {"Number puzzle", "Swipe controls", "Score tracking", "Addictive gameplay"},
},
{
id = "snake",
label = "Snake",
icon = "fa-solid fa-staff-snake",
color = "#30d158",
colorDark = "#1f9a40",
slot = 42,
installed = false,
enabled = true,
category = "games",
storeDesc = "Eat, grow and stay alive. Swipe to steer the snake and beat your best run.",
features = {"Swipe or arrow keys", "Speeds up as you grow", "High score tracking", "Smooth animations"},
},
{
id = "brickblast",
label = "Brick Blast",
icon = "fa-solid fa-table-cells-large",
color = "#ff6b35",
colorDark = "#d9491a",
slot = 43,
installed = false,
enabled = true,
category = "games",
storeDesc = "Bounce the ball, clear every brick and climb through the levels.",
features = {"Drag the paddle", "Levels that get harder", "Power ups", "High score tracking"},
},
-- ═══════════════════════════════════════════════════════════
-- MEDIA
-- ═══════════════════════════════════════════════════════════
{
id = "music",
label = "Music",
icon = "fa-solid fa-music",
color = "#fc3c44",
colorDark = "#d43039",
category = "media",
slot = 5,
installed = true,
enabled = true,
storeDesc = "Play your server's own music library and share it with people nearby.",
features = {"Your own music library", "Players submit, admins approve", "Nearby players hear your music", "Favorites, playlists & queue"},
},
-- ═══════════════════════════════════════════════════════════
-- JOB APPS (only for the jobs in AgencyConfig.JobApps)
-- Police and EMS MDT are exclusive to the Agency Pad.
-- ═══════════════════════════════════════════════════════════
{
id = "mechanic_app",
label = "Mechanic",
icon = "fa-solid fa-wrench",
color = "#ff9500",
colorDark = "#e08600",
category = "utilities",
slot = 52,
installed = false,
enabled = true,
requiresJob = true,
storeDesc = "Manage repair orders and customer requests. Accept jobs and track your workload.",
features = {"Incoming repair requests", "Job queue management", "Customer notifications", "Service history"},
},
-- ═══════════════════════════════════════════════════════════
-- SOCIAL
-- ═══════════════════════════════════════════════════════════
{
id = "snapr",
label = "Snapr",
category = "social",
icon = "fa-solid fa-ghost",
color = "#FFFC00",
colorDark = "#E0B800",
slot = 46,
installed = false,
enabled = true,
requiresLogin = false,
storeDesc = "Snaps that disappear. Point, filter, send - and it is gone once they have seen it.",
features = {"Camera with live filters", "Snaps vanish after viewing", "Send to several friends at once", "Chats with snap history"},
},
{
id = "pictogram",
label = "Pictogram",
category = "social",
icon = "fa-solid fa-camera-retro",
color = "#E1306C",
colorDark = "#C13584",
slot = 42,
installed = false,
enabled = true,
requiresLogin = true,
storeDesc = "Share photos and stories with your friends. The #1 photo sharing app.",
features = {"Photo sharing", "Stories & Reels", "Direct messages", "Follow friends"},
},
{
id = "bleeter",
label = "Bleeter",
category = "social",
icon = "fa-solid fa-hashtag",
color = "#1DA1F2",
colorDark = "#0d8bd9",
slot = 43,
installed = false,
enabled = true,
requiresLogin = true,
storeDesc = "What's happening in Los Santos? Follow trends and share your thoughts.",
features = {"Trending topics", "Share bleets", "Follow people", "Real-time feed"},
},
{
id = "recorder",
label = "Recorder",
category = "productivity",
icon = "fa-solid fa-microphone-lines",
color = "#ff453a",
colorDark = "#d92d23",
slot = 47,
installed = true,
enabled = true,
storeDesc = "Record voice memos, play them back and send them to your chats in Buzz.",
features = {"Voice memos", "Waveform playback", "Skip 15 seconds", "Send in Buzz"},
},
{
id = "lifeinvader",
label = "Life Invader",
category = "social",
icon = "fa-solid fa-thumbs-up",
color = "#4267B2",
colorDark = "#365899",
slot = 44,
installed = false,
enabled = true,
requiresLogin = true,
storeDesc = "Connect with friends, family, and the world around you.",
features = {"Friend profiles", "Status updates", "Photo albums", "Event planning"},
},
{
id = "facezoom",
label = "FaceZoom",
category = "social",
icon = "fa-solid fa-video",
color = "#2D8CFF",
colorDark = "#1a6fcc",
slot = 45,
installed = false,
enabled = true,
requiresLogin = false,
storeDesc = "Video calls and meetings with anyone, anywhere.",
features = {"Video calls", "Group meetings", "Screen sharing", "Chat messaging"},
},
-- ═══════════════════════════════════════════════════════════
-- PASSWORD MANAGER
-- ═══════════════════════════════════════════════════════════
{
id = "keychain",
label = "Keychain",
category = "utilities",
icon = "fa-solid fa-key",
color = "#8e8e93",
colorDark = "#636366",
slot = 46,
installed = true,
enabled = true,
storeDesc = "View and manage your saved passwords and app accounts.",
features = {"Saved passwords", "App accounts", "Secure storage", "Face Unlock access"},
},
-- ═══════════════════════════════════════════════════════════
-- EXAMPLE CUSTOM APP (source in apps/, off by default)
-- ═══════════════════════════════════════════════════════════
{
id = "testapp",
label = "Test App",
icon = "fa-solid fa-flask",
color = "#5856d6",
colorDark = "#4240b0",
slot = 36,
installed = false,
enabled = false,
storeDesc = "A demo app showing how custom apps work.",
},
-- ═══════════════════════════════════════════════════════════
-- AGENCY DEVICES
-- ═══════════════════════════════════════════════════════════
-- Health: condition from the phone, movement from the Agency Watch.
{
id = "health",
label = "Health",
icon = "fa-solid fa-heart-pulse",
color = "#ff375f",
colorDark = "#c72b4a",
slot = 38,
installed = true,
enabled = true,
-- Fallback text only: the Store prefers the translations in locales.js.
storeDesc = "Condition, steps, distance and pulse. It shows the most alongside an Agency Watch.",
features = {"Health and armour", "Steps and distance", "Pulse with history", "Seven-day review"},
},
{
id = "watch",
label = "Watch",
icon = "fa-solid fa-clock",
color = "#00d4ff",
colorDark = "#0090ad",
slot = 39,
installed = true,
enabled = true,
-- Fallback text only, see Health.
storeDesc = "Set up your Agency Watch completely: watch face, case, language and Agency Pay.",
features = {"Watch face and case", "Agency Pay on your wrist", "Pair the companion", "Software updates"},
},
-- Zero: call and control your own Agency Zero. Without Agency Zero on the
-- server the app explains where to get it; enabled = false hides it.
{
id = "zero",
label = "Zero",
icon = "fa-solid fa-car-side",
color = "#e2b649",
colorDark = "#a8801f",
slot = 40,
installed = true,
enabled = true,
storeDesc = "Call your Agency Zero, open its doors, lock it and see battery and range.",
features = {"Call it to where you stand", "Doors, lock and lights", "Battery and range", "Free on the Agency Store"},
},
-- Agency Demo (working custom-app template added by Claude)
{
id = "agencydemo",
label = "Agency Demo",
icon = "fa-solid fa-rocket",
color = "#00d4ff",
colorDark = "#0090cc",
slot = 37,
installed = AgencyConfig.DeveloperMode, -- only on the home screen in developer mode
enabled = AgencyConfig.DeveloperMode, -- hidden entirely when DeveloperMode = false
storeDesc = "Example custom app: identity, live server stats and notifications.",
},
}
02Arquivo SQL
Opcional: o recurso cria estas tabelas sozinho ao iniciar. Importe este arquivo só se você preparar o banco de dados manualmente:
-- Agency Phone SQL Schema
CREATE TABLE IF NOT EXISTS `agency_contacts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`name` VARCHAR(100) NOT NULL,
`number` VARCHAR(20) NOT NULL,
`is_emergency` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_messages` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`number` VARCHAR(20) NOT NULL,
`messages` LONGTEXT DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`),
KEY `number` (`number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_chirper` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) DEFAULT NULL,
`firstname` VARCHAR(50) DEFAULT NULL,
`lastname` VARCHAR(50) DEFAULT NULL,
`message` TEXT DEFAULT NULL,
`post_id` VARCHAR(30) NOT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_mail` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`recipient_email` VARCHAR(120) DEFAULT NULL,
`sender` VARCHAR(100) DEFAULT NULL,
`sender_email` VARCHAR(120) DEFAULT NULL,
`subject` VARCHAR(200) DEFAULT NULL,
`message` TEXT DEFAULT NULL,
`mail_id` INT(11) DEFAULT NULL,
`is_read` TINYINT(4) DEFAULT 0,
`button` TEXT DEFAULT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_mail_accounts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`local_part` VARCHAR(64) NOT NULL,
`email` VARCHAR(120) NOT NULL,
`label` VARCHAR(100) DEFAULT NULL,
`is_primary` TINYINT(4) DEFAULT 0,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_gallery` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`device_kind` VARCHAR(20) NOT NULL DEFAULT 'phone',
`image_url` VARCHAR(512) NOT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`),
KEY `identifier_device` (`identifier`,`device_kind`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_phone_dispatches` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`dispatch_id` INT(11) NOT NULL,
`type` VARCHAR(60) DEFAULT NULL,
`priority` VARCHAR(20) DEFAULT NULL,
`code` VARCHAR(20) DEFAULT NULL,
`label` VARCHAR(120) DEFAULT NULL,
`message` TEXT DEFAULT NULL,
`caller` VARCHAR(120) DEFAULT NULL,
`caller_phone` VARCHAR(40) DEFAULT NULL,
`location_x` FLOAT DEFAULT NULL,
`location_y` FLOAT DEFAULT NULL,
`location_z` FLOAT DEFAULT NULL,
`street` VARCHAR(160) DEFAULT NULL,
`status` VARCHAR(20) DEFAULT 'pending',
`timestamp` INT(11) DEFAULT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `dispatch_id` (`dispatch_id`),
KEY `status` (`status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_cloud_limits` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`scope_type` VARCHAR(20) NOT NULL,
`scope_key` VARCHAR(80) NOT NULL,
`storage_limit_mb` INT(11) NOT NULL DEFAULT 0,
`storage_used_mb` DECIMAL(12,2) NOT NULL DEFAULT 0.00,
`asset_limit` INT(11) NOT NULL DEFAULT 0,
`asset_count` INT(11) NOT NULL DEFAULT 0,
`purchased_storage_mb` INT(11) NOT NULL DEFAULT 0,
`purchased_asset_count` INT(11) NOT NULL DEFAULT 0,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `scope_lookup` (`scope_type`, `scope_key`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_cloud_assets` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`asset_uid` VARCHAR(64) NOT NULL,
`scope_type` VARCHAR(20) NOT NULL,
`scope_key` VARCHAR(80) NOT NULL,
`owner_identifier` VARCHAR(60) DEFAULT NULL,
`job_name` VARCHAR(60) DEFAULT NULL,
`asset_type` VARCHAR(30) NOT NULL DEFAULT 'document',
`title` VARCHAR(200) DEFAULT NULL,
`description` VARCHAR(255) DEFAULT NULL,
`url` VARCHAR(512) NOT NULL,
`mime_type` VARCHAR(100) DEFAULT NULL,
`storage_bytes` INT(11) NOT NULL DEFAULT 0,
`meta_json` LONGTEXT DEFAULT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `asset_uid` (`asset_uid`),
KEY `scope_lookup` (`scope_type`, `scope_key`),
KEY `owner_identifier` (`owner_identifier`),
KEY `job_name` (`job_name`),
KEY `asset_type` (`asset_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_phone_emails` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`email` VARCHAR(120) NOT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `identifier` (`identifier`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_app_accounts` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`app_id` VARCHAR(60) NOT NULL,
`email` VARCHAR(120) NOT NULL,
`password` VARCHAR(60) NOT NULL,
`display_name` VARCHAR(100) DEFAULT NULL,
`faceid_enabled` TINYINT(4) DEFAULT 0,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `identifier_app` (`identifier`, `app_id`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_notes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`note_id` VARCHAR(40) NOT NULL,
`title` VARCHAR(200) DEFAULT NULL,
`content` LONGTEXT DEFAULT NULL,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`),
UNIQUE KEY `note_id` (`note_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_call_history` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`caller_number` VARCHAR(20) NOT NULL,
`receiver_number` VARCHAR(20) NOT NULL,
`call_type` ENUM('incoming','outgoing','missed') DEFAULT 'outgoing',
`duration` INT(11) DEFAULT 0,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`),
KEY `caller_number` (`caller_number`),
KEY `receiver_number` (`receiver_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_darknet_purchases` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`item_id` VARCHAR(60) NOT NULL,
`item_label` VARCHAR(100) DEFAULT NULL,
`price` DECIMAL(10,4) DEFAULT 0,
`currency` VARCHAR(10) DEFAULT 'BTC',
`status` ENUM('pending','collected','expired') DEFAULT 'pending',
`pickup_x` FLOAT DEFAULT NULL,
`pickup_y` FLOAT DEFAULT NULL,
`pickup_z` FLOAT DEFAULT NULL,
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_invoices` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`sender_identifier` VARCHAR(60) NOT NULL,
`receiver_identifier` VARCHAR(60) NOT NULL,
`sender_name` VARCHAR(100) DEFAULT NULL,
`receiver_name` VARCHAR(100) DEFAULT NULL,
`amount` DECIMAL(10,2) NOT NULL,
`reason` VARCHAR(200) DEFAULT NULL,
`status` ENUM('pending','paid','declined') DEFAULT 'pending',
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `sender_identifier` (`sender_identifier`),
KEY `receiver_identifier` (`receiver_identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_phone_settings` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`setting_key` VARCHAR(60) NOT NULL,
`setting_value` TEXT DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `identifier_key` (`identifier`, `setting_key`),
KEY `identifier` (`identifier`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE IF NOT EXISTS `agency_housing` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`identifier` VARCHAR(60) NOT NULL,
`house_id` VARCHAR(100) NOT NULL,
`house_label` VARCHAR(200) DEFAULT NULL,
`housing_script` VARCHAR(60) DEFAULT NULL,
`is_locked` TINYINT(4) DEFAULT 1,
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `identifier` (`identifier`),
UNIQUE KEY `house_id` (`house_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;