Player Commands#
These commands are always available for players.
Command | Default Key | Description |
|---|---|---|
| Configurable ( | Opens or closes the smartphone |
|
|

Documentation
This section lists all available commands, exports, and events included in the script. You’ll find client-side, server-side, and shared functions designed to help developers integrate, extend, or interact with the system easily within their own scripts or frameworks.
These commands are always available for players.
Command | Default Key | Description |
|---|---|---|
| Configurable ( | Opens or closes the smartphone |
|
|
Config.Aura.pushToTalkKeyAura push-to-talk while the phone is open |
|
| Accept incoming calls while using peek mode |
|
| Reject incoming calls while using peek mode |
Explain how to register third-party applications for QS Smartphone, how the iframe bridge works, and how to communicate between the app and the phone.
-- Register a new custom application
exports['qs-smartphone']:addCustomApp({
id = 'my_app',
label = 'My App',
icon = iconUrl,
iframe = {
url = uiUrl
}
})Registers a new custom application inside QS Smartphone. Once registered, the application becomes available immediately and is automatically removed when the owning resource stops.
-- Register multiple applications
exports['qs-smartphone']:addCustomAppsBatch({
appOne,
appTwo,
appThree
})Registers multiple custom applications in a single call. This is the recommended way to initialize several apps during your resource startup.
-- Update an existing application
exports['qs-smartphone']:updateCustomApp('my_app', {
price = 500
})Updates the configuration of an existing custom application without registering it again. Only the provided fields are modified while the remaining configuration stays unchanged.
-- Remove a custom application
exports['qs-smartphone']:removeCustomApp('my_app')Removes a previously registered custom application from QS Smartphone. The application immediately becomes unavailable until it is registered again.
-- Get all registered applications
local apps = exports['qs-smartphone']:getCustomApps()
for _, app in pairs(apps) do
print(app.id)
endReturns every custom application currently registered by all running resources. This export is useful for debugging, administration, or dynamic integrations.
This section provides all available client exports for the script. These functions allow you to interact directly with the system from the client side, enabling custom features, UI interactions, and integrations with other resources. Each export includes a short description and usage example for easy implementation.
-- Check if the phone is currently open
local isOpen = exports['qs-smartphone']:IsPhoneOpen()
if isOpen then
print('Phone is open')
endReturns whether the player's phone interface is currently open. This is useful for preventing UI conflicts or delaying interactions while the phone is being used.
-- Start an audio call
local result = exports['qs-smartphone']:call('555-0100', 'audio')
if result.success then
print('Call started')
endStarts an audio or video call to the specified phone number. The export returns information about the call attempt, allowing your resource to react to successful or failed calls.
-- Open the Messages application
exports['qs-smartphone']:OpenPhoneApp('messages')Opens an application while the phone is already visible. If the phone is closed or the application does not exist, the export returns false.
-- Register a charger inside a house
exports['qs-smartphone']:BatteryRegisterHousingCharger(
houseId,
vector3(x, y, z),
2.0
)Registers a charging location that allows players to recharge their phone battery while inside a property. This export is primarily intended for housing integrations.
-- Remove a registered charger
exports['qs-smartphone']:BatteryUnregisterHousingCharger(houseId)Removes a previously registered housing charger, making it unavailable until it is registered again.
-- Display a custom Dynamic Island
exports['qs-smartphone']:showDynamicIsland({
id = 'download',
title = 'Downloading',
subtitle = 'Please wait...'
})Creates a custom Dynamic Island session that can display live information, progress, or interactive content while the player uses the phone.
-- Update an existing Dynamic Island
exports['qs-smartphone']:updateDynamicIsland('download', {
progress = 75
})Updates an existing Dynamic Island without recreating it. Any supported property can be modified while the island remains visible.
-- Hide a Dynamic Island
exports['qs-smartphone']:hideDynamicIsland('download')Removes a custom Dynamic Island from the player's screen and clears any callbacks associated with it.
-- Retrieve a Dynamic Island
local island = exports['qs-smartphone']:getDynamicIsland('download')
if island then
print(island.title)
endReturns the current state of a specific Dynamic Island. This can be useful for checking its configuration before updating it.
-- Get all active Dynamic Islands
local islands = exports['qs-smartphone']:getAllDynamicIslands()
for _, island in pairs(islands) do
print(island.id)
endReturns every custom Dynamic Island currently active for the player, allowing your resource to inspect or manage existing sessions.
-- Check if any Dynamic Island exists
if exports['qs-smartphone']:hasDynamicIsland() then
print('A custom island is active')
endReturns whether the player currently has at least one active custom Dynamic Island created through the export API.
Client events allow external resources to react to phone actions without modifying the smartphone itself.
-- Listen when the phone is opened
AddEventHandler('phone:opened', function(payload)
print(payload.phoneNumber)
end)Triggered when the player successfully opens the phone. The payload contains information about the active device, phone number, scope identifier, and UI mode.
-- Listen when the phone is closed
AddEventHandler('phone:closed', function(payload)
print(payload.reason)
end)Triggered when the player closes the phone or logs out. The payload includes the reason for the closure together with the active phone information.
-- Listen for push notifications
AddEventHandler('phone:pushNotification', function(data)
print(data.title)
end)Triggered whenever a push notification is received by the player's phone.
-- Listen for simple notifications
AddEventHandler('phone:notification', function(message, type)
print(message)
end)Triggered when a simple notification is displayed through the smartphone notification system.
-- Listen when the phone item is used
AddEventHandler('phone:usable:open', function()
print('Phone item used')
end)Triggered when the player uses the phone item and the device begins opening.
-- Listen for incoming calls
AddEventHandler('phone:incomingCall', function(callData)
print(callData.callerNumber)
end)Triggered whenever the player receives an incoming phone call.
-- Listen for call state updates
AddEventHandler('phone:callState', function(session)
print(session.phase)
end)Triggered whenever the state of an active call changes, including ringing, connected, and ended states.
-- Listen when the active phone changes
AddEventHandler('phone:device:phoneChanged', function(phone)
print(phone.phoneNumber)
end)Triggered whenever the player's active phone device changes, such as equipping another phone or swapping SIM information.
-- Listen for Dynamic Island actions
AddEventHandler('phone:dynamicIsland:action', function(islandId, actionId)
print(islandId, actionId)
end)Triggered when the player presses an action button inside an expanded Dynamic Island.
This section provides all available server exports for the script. These functions allow developers to interact with the system from the server side, manage data, trigger actions, and integrate with other resources. Each export includes a clear description and a practical example to simplify its implementation.
-- Send a push notification to a player
exports['qs-smartphone']:sendPhoneNotification(source, {
appId = 'my_app',
title = 'New Notification',
text = 'Your order is ready.'
})Sends a native push notification directly to a player's phone using their server ID. Notifications appear on the lock screen and inside the notification center if the player has an active phone.
-- Send a notification using a phone scope
exports['qs-smartphone']:sendPhoneNotificationToScope(scopeId, {
appId = 'my_app',
title = 'Dispatch',
text = 'New emergency reported.'
})Sends a push notification using a phone scope identifier instead of a server ID. This is useful when your resource already stores or works with phone scopes.
-- Get the active phone scope
local scopeId = exports['qs-smartphone']:getPhoneScopeIdentifier(source)Returns the unique phone scope associated with the player's active device. This identifier is commonly used for notifications and other phone-specific operations.
-- Create a bill
exports['qs-smartphone']:CreateBill(source, {
title = 'Mechanic',
subtitle = 'Vehicle repair',
price = 500
})Creates a new bill that appears inside the Wallet application. The player can review and pay it directly from their phone.
-- Get the player's phone number
local phoneNumber = exports['qs-smartphone']:GetCurrentPhoneNumber(source)
print(phoneNumber)Returns the active phone number assigned to the player's current device or SIM card.
-- Pay a bill
local success = exports['qs-smartphone']:PayBill(source, billId)
print(success)Attempts to pay one of the player's pending bills. The export returns whether the payment was successfully completed.
-- Retrieve unpaid bills
local bills = exports['qs-smartphone']:GetBills(source)
for _, bill in pairs(bills) do
print(bill.title)
endReturns every unpaid bill currently associated with the player, allowing your resource to inspect or display outstanding payments.
-- Get all conversations
local result = exports['qs-smartphone']:GetMessageConversations(source)
if result.ok then
for _, thread in ipairs(result.threads) do
print(thread.title)
end
endReturns the conversations available for the specified player or phone number, including unread counts, participants, and the latest message information.
-- Send a message from a custom application
exports['qs-smartphone']:SendNewMessageFromApp(
source,
'Job Center',
'Your application has been accepted.'
)Creates or reuses a conversation inside the Messages application and delivers a new message as if it was sent by the specified application. Messages can be delivered to online or offline players depending on the provided options.
-- Get unread message count
local result = exports['qs-smartphone']:GetMessageUnreadCount(source)
print(result.unreadTotal)Returns the total number of unread messages for the specified player without retrieving the full conversation list.
-- Get messages from a conversation
local result = exports['qs-smartphone']:GetThreadMessages(source, threadId)
if result.ok then
for _, message in ipairs(result.items) do
print(message.text)
end
endReturns the message history of a conversation using the same data shown inside the Messages application. Pagination can be used to load older messages.
-- Retrieve the player's mail account
local account = exports['qs-smartphone']:GetMailAccount(source)
if account then
print(account.email)
endReturns the registered mail account associated with the specified player, identifier, or email address. If no account exists, the export returns nil.
-- Send a system email
exports['qs-smartphone']:SendMail(
source,
'Welcome',
'Thanks for joining the server.'
)Sends a system email directly to the player's mailbox. Emails are delivered even if the recipient is offline, and online players can optionally receive a push notification.
-- Check if a Marketplace job exists
if exports['qs-smartphone']:JobExists('police') then
print('Marketplace job found')
endReturns whether the specified framework job has been configured as a Marketplace business.
-- Check the player's duty status
local onDuty = exports['qs-smartphone']:IsPlayerOnDuty(source)
print(onDuty)Returns whether the player is currently on duty in any Marketplace business.
-- Clock the player into duty
exports['qs-smartphone']:SetDuty(source, 'police')Changes the player's Marketplace duty status. Providing a job name places the player on duty, while omitting the job removes them from duty.
-- Get the current Marketplace duty job
local job = exports['qs-smartphone']:GetDutyJob(source)
print(job)Returns the framework job name the player is currently working as while on Marketplace duty. If the player is not on duty, the export returns nil.
-- Register an interceptor for a phone number
exports['qs-smartphone']:registerCallInterceptor('555-BUSINESS', function(callData)
return {
action = 'allow'
}
end)Registers a callback that is executed before an incoming call starts ringing. The callback can allow the call, reject it, or take full control over the call flow.
-- Check if any employee is available
local available = exports['qs-smartphone']:IsJobOnDuty('police')
print(available)Returns whether at least one employee is currently on duty for the specified Marketplace job. This is useful for dispatch systems, NPC interactions, and service availability checks.
-- Accept an intercepted call
exports['qs-smartphone']:acceptInterceptedCall(sessionId)Accepts a previously intercepted call and immediately connects both participants.
-- Remove an interceptor
exports['qs-smartphone']:unregisterCallInterceptor('555-BUSINESS')Removes a previously registered interceptor from the specified phone number. Future calls will follow the normal phone behavior.
-- Continue the normal call flow
exports['qs-smartphone']:letInterceptedCallRing(sessionId)Releases an intercepted call back to the default phone system, allowing it to ring normally for the original recipient.
-- Reject an intercepted call
exports['qs-smartphone']:rejectInterceptedCall(sessionId, 'busy')Rejects an intercepted call before it reaches the recipient. An optional reason can be provided to indicate why the call was rejected.
-- Check if a number has an interceptor
local exists = exports['qs-smartphone']:hasCallInterceptor('555-BUSINESS')
print(exists)Returns whether the specified phone number currently has one or more registered interceptors.
-- Retrieve intercepted call information
local callData = exports['qs-smartphone']:getInterceptedCallData(sessionId)
if callData then
print(callData.callerNumber)
endReturns all information associated with an intercepted call, including caller details, recipient details, and session metadata.
-- Retrieve all registered interceptors
local interceptors = exports['qs-smartphone']:getRegisteredCallInterceptors()
for number in pairs(interceptors) do
print(number)
endReturns every phone number that currently has registered interceptors, making it useful for debugging and administrative tools.
-- Check if a player is currently in a call
local inCall = exports['qs-smartphone']:isPlayerInCall(source)
print(inCall)Returns whether the specified player is currently participating in an active phone call.
-- Retrieve the current call session
local session = exports['qs-smartphone']:getActiveCallSession(source)
if session then
print(session.id)
endReturns information about the player's active call session, including the session identifier and current call state.
-- End the player's active call
exports['qs-smartphone']:endCallBySource(source)Terminates the active phone call for the specified player. This export can be used to end calls programmatically from external resources.
Server events notify external resources about important phone lifecycle events.
-- Listen when a player opens the phone
AddEventHandler('phone:opened', function(source, payload)
print(source)
end)Triggered after a player successfully opens their phone. The payload contains information about the active device and phone session.
-- Listen when a player closes the phone
AddEventHandler('phone:closed', function(source, payload)
print(payload.reason)
end)Triggered when a player closes the phone or disconnects while it is open.
-- Listen for Marketplace duty changes
AddEventHandler('qs-smartphone:marketplace:dutyChanged', function(accountId, jobName, source)
print(jobName)
end)Triggered whenever a Marketplace account changes its duty status through the smartphone or any server export.
The JavaScript Bridge allows iframe-based custom applications to communicate directly with QS Smartphone. It provides access to phone information, native dialogs, media pickers, Dynamic Island, localization, and many other built-in features.
const { bridge, api } = QSPhoneBridge.create({
appId: 'my_app',
targetOrigin: 'https://cfx-nui-qs-smartphone',
})Creates a communication bridge between your application and QS Smartphone. All bridge functionality is exposed through the returned api object.
const state = await api.getPhoneState()Returns information about the current phone state, including visibility, active application, and display mode.
const locale = await api.getPhoneLocale()Returns the language currently selected inside the smartphone.
await api.openPhoneApp('messages')Opens one of the native smartphone applications directly from your custom app.
await api.closeCurrentPhoneApp()Closes the current custom application and returns to the previous phone screen.
const theme = await api.getThemeMode()Returns the current phone theme, allowing your application to automatically adapt between light and dark mode.
const text = await api.translateText('apps.settings.language')Returns the translated value for the provided localization key using the player's selected language.
await api.showToastNotification({
title: 'Success',
text: 'Settings saved.'
})Displays a native smartphone toast notification.
const value = await api.openTextPrompt({
title: 'Rename',
placeholder: 'Name'
})Opens the native text input dialog and returns the entered value.
const value = await api.openOptionPicker({
title: 'Choose',
options: []
})Displays the native option picker and returns the selected value.
const media = await api.pickGalleryMedia()Opens the gallery and allows the player to select an existing media file.
const photo = await api.pickCameraMedia()Launches the camera application and returns the captured media after the player takes a picture.
const gif = await api.pickGif()Opens the built-in GIF picker and returns the selected GIF.
await api.showDynamicIsland({
id: 'download',
title: 'Downloading'
})Creates a Dynamic Island directly from JavaScript without requiring any Lua code.
await api.startRecorder()Starts the built-in voice recorder from within your application.
await api.stopRecorder()Stops the active voice recording session and returns the captured media if available.
bridge.emit('my:event', {
hello: true
})
bridge.onEvent((event, data) => {
console.log(event, data)
})Allows bidirectional communication between your custom application and its Lua resource, making it easy to synchronize UI interactions and gameplay logic.