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.

QS Smartphone — Developer API

Short reference for integrating external resources with qs-smartphone.

All exports use the resource name:

qs-smartphone





Starter Templates

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

Available templates:

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

These templates already include the recommended structure for iframe communication, UI integration and smartphone bridge compatibility.





Third-Party App Ecosystem

Build and integrate fully custom smartphone applications directly into Quasar Smartphone using React, jQuery or any modern web framework with iframe support and bridge communication.

Create immersive applications, App Store experiences, external interfaces and advanced integrations fully connected with the smartphone ecosystem.



Creating A Custom App

Custom applications must be registered from the client side after qs-smartphone has fully started.

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, 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


Application Structure

FieldDescription
idUnique internal application identifier
labelVisible application name inside the smartphone
iconApplication icon URL
categoryApp Store category
creatorDeveloper or creator name
descriptionDescription shown inside the App Store
appStoreOnlytrue = downloadable app, false = pre-installed
sizeMbSimulated application size shown in the App Store
iframe.urlURL loaded inside the smartphone iframe
custom.enabledEnables custom iframe functionality
bridge.enabledEnables communication bridge
allowedOriginsAllowed iframe origins for secure communication





Custom App Exports

ExportDescription
addCustomApp(payload)Register a single application
addCustomAppsBatch(payloads)Register multiple applications at once
updateCustomApp(appId, patch)Update fields from an existing application
removeCustomApp(appId)Remove an application by id
getCustomApps()Returns all registered applications

Applications are automatically removed when the owner resource stops.

Built-in native applications such as:

radio crime

and other internal smartphone apps are excluded from automatic removal.





Push Notification Server

Send lock-screen or banner notifications directly to a player phone.

The player must have an active phone scope before receiving scoped notifications.

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, }) if not ok then print('Notification failed:', err) end

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

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

Returns:

success, errorCode, data

Common errors include:

INVALID_SOURCE NO_SCOPE INVALID_PAYLOAD





Phone Number And Scope

Use these server exports to get the player phone identity.

local scopeId = exports['qs-smartphone']:getPhoneScopeIdentifier(source) local number = exports['qs-smartphone']:GetCurrentPhoneNumber(source)
ExportDescription
getPhoneScopeIdentifier(source)Returns the persistent phone scope used for notifications and data isolation
GetCurrentPhoneNumber(source)Returns the active SIM or metadata phone number for the player





Check If Phone Is Open

Use this client export to check if the phone UI is currently visible.

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

This is useful when you want to prevent duplicated UI actions or only execute logic while the phone is open.





Start A Call

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

Available call types:

audio video

callerNumberOverride is optional and can be used when your script needs to display a custom caller number.



Open A Phone App

Open a specific phone app while the phone is visible.

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

This export returns false if the phone is closed or if the app ID is invalid.

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



Inventory Item Exports

These server exports are designed for inventory items, usable handlers or ox_inventory item definitions.

exports['qs-smartphone']:useSimCard(event, item, inventory, slot)
exports['qs-smartphone']:usePowerbank(source)
exports['qs-smartphone']:useWirelessEarbuds(...)
ExportUse
useSimCard(...)Handles SIM card item usage
usePowerbank(source)Uses a power bank to charge the phone
useWirelessEarbuds(...)Handles wireless earbuds usage





Housing Battery Charger

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

exports['qs-smartphone']:BatteryRegisterHousingCharger(houseId, vector3(x, y, z), 2.0)
exports['qs-smartphone']:BatteryUnregisterHousingCharger(houseId)
ExportDescription
BatteryRegisterHousingCharger(houseId, coords, radius)Registers a charger location inside a house
BatteryUnregisterHousingCharger(houseId)Removes the charger linked to that house





Iframe JavaScript Bridge

Custom iframe apps can communicate with the smartphone using the JavaScript bridge SDK.

Load the SDK 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', })

Wait until the phone bridge is ready:

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

Get the current phone state:

const state = await api.getPhoneState()

Example returned state:

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


JavaScript Bridge API Methods

Common methods available through api:

MethodDescription
getPhoneState()Returns current phone visibility, mode, active app and screen
openPhoneApp(appId)Opens another phone app
closeCurrentPhoneApp()Closes the current app
getThemeMode()Returns the current phone theme mode
translateText(key)Returns a translated phone text
showToastNotification(payload)Shows a toast notification
openTextPrompt(payload)Opens a text input prompt
openOptionPicker(payload)Opens an option selector
pickGalleryMedia(payload)Opens the gallery picker
pickGif()Opens GIF picker
startRecorder()Starts recorder
stopRecorder()Stops recorder

Example toast:

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

Example text prompt:

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

Example gallery picker:

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





Custom Bridge Events

Use bridge events to communicate between your iframe UI and your Lua resource.

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

Listen for custom events:

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

Use this for advanced integrations where your custom app needs to send actions to your Lua logic.



Client Events

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

EventUse
phone:pushNotificationShows a push notification in the phone UI
phone:notificationShows a simple toast notification
phone:usable:openTriggered when the player uses the phone item
phone:incomingCallTriggered when a call is received
phone:callStateSends call session updates

Example client push notification without exports:

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





Custom Framework Hooks

Framework and notification behavior can be edited inside:

qs-smartphone/custom/

Available files:

custom/client.lua custom/server.lua custom/<framework>/client.lua custom/<framework>/server.lua
FileUse
custom/client.luaClient notifications and 3D text helpers
custom/server.luaServer notifications and phone push notification handlers
custom/<framework>/client.luaESX / QB / framework client bridge
custom/<framework>/server.luaESX / QB / framework server bridge

Useful server functions:

Notification(src, msg, type) PhonePushNotification(scopeId, payload)

General behavior can also be configured inside:

config/main.lua

This includes item name, require item behavior, debug mode, store settings and more.





NUI Callback Custom App To Game

Register callbacks inside your own client resource when your custom app needs to communicate with the game.

RegisterNUICallback('my-app:action', function(data, cb) cb({ ok = true, result = 'done' }) end)

From your React, Vue or custom UI, use the standard FiveM fetchNui pattern targeting your own resource name.

The starter template includes an example:

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

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