Quasar Store Logo

Developer API

This section explains the main exports, helpers, events and bridge tools available for developers who want to integrate their own scripts with qs-smartphone.

Starter templates

Quasar Smartphone includes starter templates to help developers create custom applications faster.

Available templates:

[phone]/[template]/phone-custom-react [phone]/[template]/phone-custom-jquery

These templates already include the recommended structure for:

iframe communication
phone bridge compatibility
custom UI integration
FiveM NUI communication
React or jQuery-based custom apps

Use these templates if you want to build your own phone application without starting from zero.



Custom app iframe integration

Custom apps are external UIs that run inside the smartphone using an iframe.

This allows you to create apps using:

React
jQuery
Vue
plain HTML/CSS/JavaScript
any modern web framework that supports iframe usage

Custom apps must be registered from the client side of your resource, after qs-smartphone has fully started.



Registering a custom app

Basic example:

local ui = 'https://cfx-nui-' .. GetCurrentResourceName() .. '/ui/build/' local ok, err = exports['qs-smartphone']:addCustomApp({ id = 'my_app', label = 'My App', icon = ui .. 'icon.webp', category = 'Utilities', creator = 'Your Name', description = 'Short description for the store.', appStoreOnly = true, -- false = pre-installed on home screen price = 450, -- optional; if > 0 app requires payment in App Store sizeMb = 5, iframe = { url = ui .. 'index.html' }, custom = { enabled = true, bridge = { enabled = true, allowedOrigins = { 'https://cfx-nui-' .. GetCurrentResourceName() }, }, }, }) if not ok then print('addCustomApp failed:', err) end


Custom app fields

FieldTypeDescription
idstringUnique app identifier. Use lowercase and avoid spaces.
labelstringName displayed to the player.
iconstringApp icon URL. Usually points to your NUI build folder.
categorystringApp Store category. Example: Utilities, Games, Business.
creatorstringDeveloper or studio name.
descriptionstringShort App Store description.
appStoreOnlybooleanIf true, the app appears only in the App Store. If false, it is pre-installed.
pricenumberOptional App Store price. If greater than 0, the player must buy it.
sizeMbnumberVisual download size shown in the App Store.
iframe.urlstringURL of your custom app HTML.
custom.enabledbooleanEnables custom app behavior.
custom.bridge.enabledbooleanEnables the JavaScript bridge.
custom.bridge.allowedOriginstableAllowed NUI origins that can communicate with the phone.


App Store price

You can make a custom app free or paid.

Free app:

price = 0

Paid app:

price = 450

You can also update the price later:

exports['qs-smartphone']:updateCustomApp('my_app', { price = 900})

This is useful for dynamic prices, premium DLCs, temporary discounts or roleplay economy systems.



Custom app exports

These exports are used to manage custom apps dynamically.

ExportDescription
addCustomApp(payload)Registers one custom app. Returns success, errorCode.
addCustomAppsBatch(payloads)Registers multiple custom apps at once.
updateCustomApp(appId, patch)Updates specific fields of an existing app.
removeCustomApp(appId)Removes a custom app by its app ID.
getCustomApps()Returns the list of registered custom apps.


Register multiple apps

exports['qs-smartphone']:addCustomAppsBatch({ { id = 'app_one', label = 'App One', icon = ui .. 'app_one.webp', category = 'Utilities', iframe = { url = ui .. 'app_one.html' }, custom = { enabled = true } }, { id = 'app_two', label = 'App Two', icon = ui .. 'app_two.webp', category = 'Business', iframe = { url = ui .. 'app_two.html' }, custom = { enabled = true } } })


Update an app

exports['qs-smartphone']:updateCustomApp('my_app', { label = 'My Updated App', price = 900, category = 'Business' })

Only the fields included in the patch are updated.



Remove an app

exports['qs-smartphone']:removeCustomApp('my_app')


Get all custom apps

local apps = exports['qs-smartphone']:getCustomApps()print(json.encode(apps))


Automatic app removal

Custom apps are automatically removed when the owner resource stops.

Example:

ensure my-custom-phone-app

If my-custom-phone-app stops, its registered apps are removed automatically.

Built-in native smartphone apps are excluded from automatic removal, such as:

radiocrime

and other internal phone applications.



Push notifications server side

You can send lock-screen or banner notifications directly to a player phone.

This is useful for:

delivery alerts
job notifications
banking messages
dispatch alerts
marketplace orders
custom app notifications
mission updates

To send a scoped notification, the player must have an active phone scope.



Send notification using phone scope

local scopeId = exports['qs-smartphone']:getPhoneScopeIdentifier(source) if not scopeId then return end local ok, err = exports['qs-smartphone']:sendPhoneNotificationToScope(scopeId, { appId = 'my_app', appName = 'My App', title = 'New order', subtitle = 'Shop', text = 'Your package is ready for pickup.', closeTimeout = 5000, })


Notification payload

FieldTypeDescription
appIdstringApp identifier related to the notification.
appNamestringApp display name.
titlestringMain notification title.
subtitlestringOptional subtitle.
textstringNotification body text.
closeTimeoutnumberTime in milliseconds before closing automatically.


Send notification using player server ID

You can also send a notification directly using the player server ID:

exports['qs-smartphone']:sendPhoneNotification(source, { appId = 'my_app', title = 'Hello', text = 'World', })

This is simpler when you already have the player source.



Notification return values

Notification exports return:

success, errorCode, data

Common errors:

ErrorMeaning
INVALID_SOURCEThe player source is invalid.
NO_SCOPEThe player does not have an active phone scope.
INVALID_PAYLOADThe notification data is missing or invalid.

Example:

local success, errorCode, data = exports['qs-smartphone']:sendPhoneNotification(source, { appId = 'my_app', title = 'Hello', text = 'World', }) if not success then print('Phone notification error:', errorCode) end


Phone number and scope server exports

These exports allow you to get the player phone identity.



Get phone scope identifier

local scopeId = exports['qs-smartphone']:getPhoneScopeIdentifier(source)

The scope ID is a persistent identifier used for:

notifications
phone data isolation
app-specific data
identifying the active phone environment

Use this when your system needs to communicate with the correct phone instance.



Get current phone number

local number = exports['qs-smartphone']:GetCurrentPhoneNumber(source)

This returns the active SIM or metadata phone number for the player.

Use it when you need to:

display the player phone number
start external phone interactions
link app data to a phone number
validate phone ownership


Client helpers

Client helpers are exports used from your client-side Lua files.



Check if the phone is open

local open = exports['qs-smartphone']:IsPhoneOpen()

Returns true if the phone UI is currently visible.

Returns false if the phone is closed.

Example:

if exports['qs-smartphone']:IsPhoneOpen() then print('The phone is currently open') else print('The phone is closed') end

This is useful when you want to:

prevent duplicated UI actions
avoid opening another menu over the phone
only execute logic while the phone is visible
block certain actions while the phone is open


Start a call

You can start an audio or video call from your client resource.

local result = exports['qs-smartphone']:call('555-0100', 'audio', { callerNumberOverride = '555-9999', }) if result.success then print('Call started', json.encode(result.data)) else print(result.error, result.message) end


Call types

Available call types:

audiovideo

Example video call:

local result = exports['qs-smartphone']:call('555-0100', 'video')


Custom caller number

callerNumberOverride is optional.

Use it when your script needs to display a custom caller number.

Example:

local result = exports['qs-smartphone']:call('555-0100', 'audio', { callerNumberOverride = 'Anonymous' })

This can be useful for:

anonymous calls
business calls
police dispatch calls
public phones
job systems
scripted missions


Open a phone app

You can open a specific phone app while the phone is visible.

exports['qs-smartphone']:OpenPhoneApp('messages')

This export returns false if:

the phone is closed
the app ID is invalid
the app does not exist

Example:

local opened = exports['qs-smartphone']:OpenPhoneApp('messages') if not opened then print('Could not open app. Phone may be closed or app ID is invalid.') end

Use this when you want to redirect players to a specific app from another script.

Examples:

exports['qs-smartphone']:OpenPhoneApp('bank') exports['qs-smartphone']:OpenPhoneApp('messages') exports['qs-smartphone']:OpenPhoneApp('camera') exports['qs-smartphone']:OpenPhoneApp('my_app')


Housing battery charger qs-housing

If you use qs-housing, you can register or remove phone battery charger points inside houses.

This allows players to charge their phone inside custom housing locations.



Register a housing charger

exports['qs-smartphone']:BatteryRegisterHousingCharger(houseId, vector3(x, y, z), 2.0)

Parameters:

ParameterDescription
houseIdUnique house identifier.
vector3(x, y, z)Charger position inside the house.
2.0Interaction distance.

Example:

exports['qs-smartphone']:BatteryRegisterHousingCharger('house_1', vector3(123.4, 456.7, 78.9), 2.0)


Remove a housing charger

exports['qs-smartphone']:BatteryUnregisterHousingCharger(houseId)

Example:

exports['qs-smartphone']:BatteryUnregisterHousingCharger('house_1')

Use this when:

a house is deleted
a house shell is unloaded
a charger position is removed
a housing instance is closed


Iframe JavaScript bridge

The JavaScript bridge allows your custom iframe app to communicate with the smartphone.

It gives your app access to phone features such as:

phone state
current language
theme mode
translations
toast notifications
text prompts
option pickers
gallery picker
camera picker
GIF picker
recorder functions
opening and closing apps
custom bridge events


Load the bridge SDK

Add this script inside your custom app HTML:

<script src="https://cfx-nui-qs-smartphone/web/build/bridge/qs-phone-bridge.js"></script>


Create the bridge connection

const { bridge, api } = QSPhoneBridge.create({ appId: 'my_app', targetOrigin: 'https://cfx-nui-qs-smartphone', }) api.onReady(() => { console.log('Phone bridge ready') }) const state = await api.getPhoneState() // { visible, mode, activeApp, screen } const locale = await api.getPhoneLocale() // e.g. "tr", "en", "de" await api.showToastNotification({ title: 'Done', text: 'Saved successfully', }) const value = await api.openTextPrompt({ title: 'Rename', placeholder: 'Name', }) const media = await api.pickGalleryMedia({ mediaFilter: 'photos' }) const photo = await api.pickCameraMedia() // Opens Camera → capture → returns full gallery row { id, url, location, ... } or null on cancel
FieldDescription
appIdYour custom app ID. Must match the Lua registered app ID.
targetOriginThe phone NUI origin. Usually https://cfx-nui-qs-smartphone.


Wait until the bridge is ready

api.onReady(() => { console.log('Phone bridge ready') })

Always wait for the bridge to be ready before using phone API methods.



Get current phone state

const state = await api.getPhoneState()

Example returned state:

{ visible: true, mode: 'default', activeApp: 'my_app', screen: 'home' }

Use this to know:

if the phone is visible
which app is active
which screen is currently displayed
the current phone mode


Get current phone language

const locale = await api.getPhoneLocale()

Example result:

'en'

Other examples:

trdeesfrpt

Use this to make your app adapt to the player phone language.



Translate phone text

const title = await api.translateText('apps.settings.language')

Example:

const { api } = QSPhoneBridge.create({ appId: 'my_app', targetOrigin: 'https://cfx-nui-qs-smartphone', }) const locale = await api.getPhoneLocale() const title = await api.translateText('apps.settings.language') console.log('active locale', locale, 'sample translation', title)

This is useful if your app wants to reuse phone translations or stay consistent with the global smartphone language system.



Show toast notification

await api.showToastNotification({ title: 'Done', text: 'Saved successfully', })

Use this for small app notifications inside the phone UI.



Open text prompt

const value = await api.openTextPrompt({ title: 'Rename', placeholder: 'Name', })

This opens a text input prompt inside the phone.

Example:

const name = await api.openTextPrompt({ title: 'Create contact', placeholder: 'Contact name', }) if (name) { console.log('Player entered:', name) }


Open option picker

const option = await api.openOptionPicker({ title: 'Select option', options: [ { label: 'Option 1', value: 'one' }, { label: 'Option 2', value: 'two' } ] })

Use this when the player needs to choose between multiple options.



Pick gallery media

const media = await api.pickGalleryMedia({ mediaFilter: 'photos' })

Example filters:

photos videos all

This lets the player select media from the phone gallery.



Pick camera media

const photo = await api.pickCameraMedia()

This opens the Camera app, allows the player to capture a photo, and returns the full gallery row.

Example returned data:

{ id: 25, url: 'https://...', location: 'Los Santos', createdAt: 1710000000 }

If the player cancels, it returns:

null


Pick GIF

const gif = await api.pickGif()

Use this when your app needs GIF selection support.



Recorder API

Start recorder:

await api.startRecorder()

Stop recorder:

const recording = await api.stopRecorder()

Use this for custom apps that need voice notes, reports, audio logs or immersive roleplay recordings.



Open another phone app from iframe

await api.openPhoneApp('messages')

Example:

await api.openPhoneApp('camera')


Close current phone app

await api.closeCurrentPhoneApp()

Use this when your custom app needs to exit itself or return the player to the phone interface.



Get theme mode

const theme = await api.getThemeMode()

This allows your iframe app to detect if the phone is using light or dark mode.

Use it to adapt your custom app style automatically.



Common bridge API methods

MethodDescription
getPhoneState()Returns current phone state.
getPhoneLocale()Returns current phone language.
openPhoneApp(appId)Opens another phone app.
closeCurrentPhoneApp()Closes the current app.
getThemeMode()Returns current theme mode.
translateText(key)Returns translated text from a locale key.
showToastNotification(payload)Shows a phone toast notification.
openTextPrompt(payload)Opens a text input prompt.
openOptionPicker(payload)Opens an option selector.
pickGalleryMedia(payload)Opens gallery picker.
pickCameraMedia()Opens camera capture flow.
pickGif()Opens GIF picker.
startRecorder()Starts audio recording.
stopRecorder()Stops audio recording and returns data.


Template usage

Both starter templates use the same bridge API.

Example:

const { api } = QSPhoneBridge.create({ appId: 'my_app', targetOrigin: 'https://cfx-nui-qs-smartphone', }) const locale = await api.getPhoneLocale() const title = await api.translateText('apps.settings.language') console.log( 'active locale', locale, 'sample translation', title )

This means you can build your app in React or jQuery and still use the same smartphone bridge methods.



Custom bridge events

You can use bridge events to communicate between your iframe UI and your Lua resource.

This is useful for advanced integrations where your custom app needs to send actions to your game logic.



Emit a custom event

bridge.emit('my:event', { value: true })


Listen for custom events

bridge.onEvent((event, data) => { console.log(event, data) })

Example:

bridge.onEvent((event, data) => { if (event === 'my:event') { console.log('Received custom event:', data) } })


Built-in bridge events

The phone can send built-in events to your iframe app.

EventPayloadDescription
phone.theme.changed`{ mode: 'light''dark', darkMode: boolean }`
phone.locale.changed{ language: string }Triggered when the player changes phone language in Settings.
app:openedApp dataTriggered when an app is opened.
app:closedApp dataTriggered when an app is closed.


Theme change example

bridge.onEvent((event, data) => { if (event === 'phone.theme.changed') { console.log('Theme changed:', data.mode) if (data.darkMode) { document.body.classList.add('dark') } else { document.body.classList.remove('dark') } } })


Locale change example

bridge.onEvent((event, data) => { if (event === 'phone.locale.changed') { console.log('Language changed:', data.language) } })


Client events

You can listen to these events inside your own client resource.

EventUse
phone:pushNotificationShows a phone notification using the same payload as server push.
phone:notificationShows a simple ox_lib or qs-interface toast using msg and type.
phone:usable:openTriggered when the player uses the phone item. Useful if you need to open the UI manually.
phone:incomingCallTriggered when the player receives an incoming call.
phone:callStateTriggered when the call session state changes.


Trigger a phone notification without exports

You can also trigger a client notification directly from Lua:

TriggerClientEvent('phone:pushNotification', source, { appId = 'my_app', title = 'Title', text = 'Body text', })


Listen to incoming call

RegisterNetEvent('phone:incomingCall', function(payload) print('Incoming call:', json.encode(payload)) end)


Listen to call state updates

RegisterNetEvent('phone:callState', function(payload) print('Call state changed:', json.encode(payload)) end)


NUI callback custom app to game

When your custom iframe app needs to communicate with your Lua resource, use standard FiveM NUI callbacks.

Register the callback inside your own client resource:

RegisterNUICallback('my-app:action', function(data, cb) print('Received data from custom app:', json.encode(data)) cb({ ok = true, result = 'done' }) end)

From React, Vue, jQuery or plain JavaScript, use the standard FiveM fetchNui pattern targeting your own resource name.

The recommended template already includes an example:

[phone]/[template]/phone-custom-react

This is the recommended way to connect your custom app interface with Lua actions.



Recommended custom app structure

Example resource structure:

my-phone-app/ ├── fxmanifest.lua ├── client.lua ├── server.lua └── ui/ └── build/ ├── index.html ├── icon.webp ├── assets/ └── static/

Example fxmanifest.lua:

fx_version 'cerulean' game 'gta5' author 'Your Name' description 'Custom QS Smartphone App' version '1.0.0' client_scripts { 'client.lua' } server_scripts { 'server.lua' } ui_page 'ui/build/index.html' files { 'ui/build/index.html', 'ui/build/icon.webp', 'ui/build/**/*' } dependency 'qs-smartphone'


Best practices

Use unique app IDs

Good:

id = 'my_bank_app'

Bad:

id = 'bank'

Avoid using IDs that may conflict with built-in phone apps.



Register apps after qs-smartphone starts

Your resource should start after qs-smartphone.

Example server.cfg:

ensure qs-smartphone ensure my-phone-app


Always check return values

local ok, err = exports['qs-smartphone']:addCustomApp(payload) if not ok then print('Could not register app:', err) end


Use allowedOrigins correctly

Your allowedOrigins should match your resource NUI origin:

allowedOrigins = { 'https://cfx-nui-' .. GetCurrentResourceName() }

If the origin is wrong, the bridge may not communicate correctly.



Keep icons optimized

Recommended icon format:

.webp

Recommended usage:

icon = ui .. 'icon.webp'

Use square icons with a clean design for the best App Store appearance.



Use the bridge for phone features

Do not recreate phone systems manually if the bridge already provides them.

Use:

api.pickGalleryMedia() api.pickCameraMedia() api.openTextPrompt() api.showToastNotification() api.translateText()

instead of building separate duplicated systems.



Quick example: complete custom app flow

1
Create your resource.
2
Add your UI insideui/build/.
3
Add your icon asicon.webp.
4
Register the app fromclient.lua.
5
Load the bridge SDK in your HTML.
6
UseQSPhoneBridge.create().
7
Useapimethods to interact with the phone.
8
Use NUI callbacks to communicate with Lua.
9
Use push notifications when your app needs to alert the player.


Example client.lua

CreateThread(function() Wait(2000) local ui = 'https://cfx-nui-' .. GetCurrentResourceName() .. '/ui/build/' local ok, err = exports['qs-smartphone']:addCustomApp({ id = 'my_app', label = 'My App', icon = ui .. 'icon.webp', category = 'Utilities', creator = 'Your Name', description = 'My first custom QS Smartphone app.', appStoreOnly = true, price = 0, sizeMb = 5, iframe = { url = ui .. 'index.html' }, custom = { enabled = true, bridge = { enabled = true, allowedOrigins = { 'https://cfx-nui-' .. GetCurrentResourceName() }, }, }, }) if not ok then print('addCustomApp failed:', err) end end) RegisterNUICallback('my-app:action', function(data, cb) print('Custom app action:', json.encode(data)) cb({ ok = true, result = 'done' }) end)



Example index.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>My App</title> </head> <body> <h1>My App</h1> <button id="toast"> Show Toast </button> <script src="https://cfx-nui-qs-smartphone/web/build/bridge/qs-phone-bridge.js"></script> <script> const { bridge, api } = QSPhoneBridge.create({ appId: 'my_app', targetOrigin: 'https://cfx-nui-qs-smartphone', }) api.onReady(async () => { console.log('Phone bridge ready') const state = await api.getPhoneState() console.log('Phone state:', state) const locale = await api.getPhoneLocale() console.log('Phone locale:', locale) }) document .getElementById('toast') .addEventListener('click', async () => { await api.showToastNotification({ title: 'Success', text: 'This toast comes from a custom app.' }) }) bridge.onEvent((event, data) => { console.log('Bridge event:', event, data) }) </script> </body> </html>





Toggle Disabled

Enables or disables the smartphone completely, preventing players from opening or interacting with it. You can also check the current disabled state at any time.

-- Disable phone usage exports['qs-smartphone']:ToggleDisabled(true) -- Enable phone usage exports['qs-smartphone']:ToggleDisabled(false) -- Check if the phone is disabled local disabled = exports['qs-smartphone']:IsDisabled()

Disable smartphone

exports['qs-smartphone']:ToggleDisabled(true)

Enable smartphone

exports['qs-smartphone']:ToggleDisabled(false)

Check disabled state

local disabled = exports['qs-smartphone']:IsDisabled()





Send New Message From App

Sends a message directly to the Messages app as if it were sent by a system application or server script. The export automatically creates (or reuses) a conversation using the provided app name and can optionally display a push notification to the player.

-- Send by phone number exports['qs-smartphone']:SendNewMessageFromApp( '555-0100', 'Bank', 'Your account has been credited with $500.' ) -- Send by player source exports['qs-smartphone']:SendNewMessageFromApp( playerId, 'Job Center', 'Your application has been approved.' )



Full Configuration

exports['qs-smartphone']:SendNewMessageFromApp({ source = playerId, appLabel = 'City Hall', message = 'Congratulations! You have been hired as a mechanic.', requireOnline = false, push = { title = 'City Hall', text = 'You have a new message', closeTimeout = 4500, metadata = { reason = 'job_offer' } } })



Parameters

You can target a player using either their server ID or phone number.

source = playerId

or

targetPhone = '555-0100'



App label

Defines the conversation name shown inside the Messages app.

appLabel = 'City Hall'



Message

The text content that will be delivered to the player.

message = 'Congratulations! You have been hired as a mechanic.'



Require online

Determines whether the player must be connected to receive the message.

requireOnline = true

Player must be online or the message will not be sent.

requireOnline = false

Message is saved and delivered even if the player is offline.



Push notification

Displays a notification when the message arrives.

push = { title = 'City Hall', text = 'You have a new message', closeTimeout = 4500 }



Disable push notification

Send the message silently without showing a notification.

push = false



Push metadata

Attach custom data that can be used by integrations or custom applications.

metadata = { reason = 'job_offer' }



Examples

Bank notification

exports['qs-smartphone']:SendNewMessageFromApp( playerId, 'Bank', 'Your account has been credited with $500.' )

Government message

exports['qs-smartphone']:SendNewMessageFromApp({ source = playerId, appLabel = 'City Hall', message = 'Your license has been approved.' })

Silent message

exports['qs-smartphone']:SendNewMessageFromApp({ source = playerId, appLabel = 'Police Department', message = 'Case file updated.', push = false })

Offline delivery

exports['qs-smartphone']:SendNewMessageFromApp({ targetPhone = '555-0100', appLabel = 'Job Center', message = 'Your application has been approved.', requireOnline = false })





Marketplace Shop Duty

Control and query the Marketplace app duty system directly from server-side scripts. This system manages the Enter Service and Exit Service actions available inside the Marketplace Profile tab.

Unlike the Settings Job Duty toggle (on_duty), Marketplace Duty is linked to the player's active Marketplace session and determines whether they are available as staff inside the Marketplace application.

All exports automatically resolve jobs configured in Config.Marketplace.Shops, so you only need to provide the framework job name. All exports are server-side and use the resource name qs-smartphone.

Check if a job exists

Verify whether a framework job is configured as a Marketplace shop.

if exports['qs-smartphone']:JobExists('police') then print('Police shop is available') end

Return value

boolean

Returns true if the job exists inside Config.Marketplace.Shops.

Parameters

Framework job name configured in the Marketplace.

'police'

Job names are case-insensitive.

'Police' 'POLICE' 'police'

All values are treated as the same job.





Check if a player is on duty

Determine whether a player is currently working in any Marketplace shop.

local onDuty = exports['qs-smartphone']:IsPlayerOnDuty(source)

Return value

boolean

Returns true when the player is currently on duty.

Parameters

Server ID of the target player.

source





Get player's active duty job

Retrieve the Marketplace job currently assigned to a player.

local jobName = exports['qs-smartphone']:GetDutyJob(source)

Return value

string | nil

Returns the framework job name while on duty.

'police' 'ambulance' 'mechanic'

Returns nil if the player is not currently on duty.

Parameters

Server ID of the target player.

source





Set player duty status

Clock a player into a Marketplace shop or remove them from duty.

Start duty

exports['qs-smartphone']:SetDuty(source, 'police')

Stop duty

exports['qs-smartphone']:SetDuty(source)

Return value

boolean

Returns true when the operation succeeds.

Parameters

Server ID of the target player.

source

Framework job name configured in Marketplace.

'police'

If omitted, the player will be removed from duty.





Check if a job has active staff

Determine whether at least one employee is currently on duty for a specific Marketplace job.

local available = exports['qs-smartphone']:IsJobOnDuty('police')

Return value

boolean

Returns true when at least one staff member is currently on duty.

Parameters

Framework job name configured in Marketplace.

'police'

Example

if exports['qs-smartphone']:IsJobOnDuty('ambulance') then print('Medical staff available') end