> For the complete documentation index, see [llms.txt](https://docs.gkshop.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.gkshop.org/gksphone-v2/exports-and-events/client-exports.md).

# Client Exports

## **Notification**

### **Send Notification**

```lua

local NotifData = {
    title = "Notification header", -- Notification header
    message = "Notification Message", -- Notification content message
    icon    = '/html/img/icons/messages.png', -- Icon of the notification
    duration = 5000, -- specify how many seconds,
    type = "success", -- the home screen will also appear on the notification side.
    buttonactive = false, -- Activate if you want to use the button function
    button = {
       buttonEvent = "gksphone:client:Test", -- event name to use if the button approves
       buttonData = "test", -- If you want to transfer any data in the button
    }
}
exports["gksphone"]:Notification(NotifData)
```

## Mail

### Send Mail

```lua
local waitingDelivery = { location = { x = 0, y = 0, z = 0 }, name = "Test Location" }
local MailData = {
  sender = 'GKSHOP',
  image = '/html/img/icons/mail.png',
  subject = "GKSPHONE",
  message = 'TEST',
  button = {   --- If you don't want it to be a button, please remove it.
       enabled = true,
       buttonEvent = "gksphone:client:mailtest",
       buttonData = waitingDelivery,  -- data
       buttonname = "Test Button"
  }
}
exports["gksphone"]:SendNewMail(MailData)

------

RegisterNetEvent("gksphone:client:mailtest", function (data)
    debugprint("gksphone:client:mailtest")
    print(data.name)  -- Test Location
    print(data.location) -- { x = 0, y = 0, z = 0 }
end)
```

## Call

### Create Call

```lua
-- Number
exports['gksphone']:CreateCall({ number = "5551234" })

-- Hide number 
exports['gksphone']:CreateCall({ number = "5551234", hideNumber = true })

-- Job / company (Config.JOBServices key)
exports['gksphone']:CreateCall({ job = "police" })

-- Video
exports['gksphone']:CreateCall({ number = "5551234", videoCall = true })

local ok, reason = exports['gksphone']:CreateCall({ job = "police" })
-- false reasons: invalid_data | already_in_call | invalid_job | missing_number

```

### End Call <a href="#endcall" id="endcall"></a>

```lua
exports["gksphone"]:EndCall()
```

### Is In Call <a href="#isincall" id="isincall"></a>

```lua
local inCall = exports["gksphone"]:IsInCall()
print(inCall) -- true or false
```

### CreateCallNumber

<pre class="language-lua"><code class="lang-lua">-- Do not use the number in the service application
---@class IncomingCall
---@field id string
---@field accept fun()
---@field deny fun()
<strong>local createcall, reason = exports['gksphone']:CreateCallNumber("911", {
</strong>    displayName = "Police",
    onCall = function(incomingCall)
        print("Incoming call from: " .. incomingCall.id)
        Wait(6000)  -- 6sn
        incomingCall.accept() -- Automatically accept the call
    end,
    onEnd = function()
        print("Call ended")
    end
})
if createcall then
    print("Create call created successfully")
else
    print("Failed to create custom call")
end
</code></pre>

### RemoveCallNumber

```lua
local removecall, reason = exports['gksphone']:RemoveCallNumber("911")
if removecall then
    print("Call deleted successfully")
else
    print(reason)
end
```

### CallEndCustom

```lua
exports['gksphone']:CallEndCustom()
```

## Custom App

### Add Custom App

```lua
exports['gksphone']:AddCustomApp({
    name        = "MyApp",                                       -- (required) Unique app name
    appurl      = "https://cfx-nui-my-resource/ui/index.html",   -- (required) App iframe URL
    icons       = "https://cfx-nui-my-resource/ui/icon.png",     -- App icon
    description = "My awesome app",                               -- App Store description
    show        = true,                                           -- Show in App Store (default: true)
    startapp    = false,                                          -- Auto-add to home page (default: false)
    signal      = false,                                          -- Require phone signal
    allowjob    = {},                                             -- Job whitelist e.g. { "police", "ambulance" }
    blockedjobs = {},                                             -- Job blacklist e.g. { "unemployed" }
    labelLangs  = {                                               -- Localized app name (optional, falls back to name)
        tr = "Uygulamam",
        en = "My App",
        de = "Meine App"
    },

    -- ▶ Lifecycle Callbacks (optional)
    onOpen  = function(phoneUniqueId, phoneNumber)
        print(("App opened | Phone: %s | Number: %s"):format(phoneUniqueId, phoneNumber))
    end,
    onClose = function(phoneUniqueId, phoneNumber)
        print(("App closed | Phone: %s | Number: %s"):format(phoneUniqueId, phoneNumber))
    end
})
```

## Custom Widget

### Add Custom Widget

```lua
exports['gksphone']:AddCustomWidget({
    id          = "demo-widget",                                      -- (required) Unique widget id
    widgetUrl   = "https://cfx-nui-custom-widget/ui/widget.html",    -- (required) Widget iframe URL
    title       = "Demo Widget",                                      -- Gallery title
    description = "Example custom home widget",                       -- Gallery subtitle
    icon        = "",                                                 -- icon
    size        = "2x2",                                              -- "1x1" | "2x2" | "4x2" | "4x4"
    show        = true,                                               -- Show in gallery (default: true)
    labelLangs  = {                                                   -- Localized title (optional)
        tr = "Demo Widget",
        en = "Demo Widget",
        de = "Demo Widget"
    }
})
```

### Remove Custom Widget

```lua
exports['gksphone']:RemoveCustomWidget("demo-widget")
```

## Live Activity

Glanceable status cards shown on the Dynamic Island and lock screen

#### StartLiveActivity <a href="#startliveactivity" id="startliveactivity"></a>

```lua
local activity = {
    id       = "delivery:1234",   -- required, unique per activity
    app      = "courier",         -- source app key
    title    = "Delivery",        -- card headline
    subtitle = "Heading to drop", -- optional line under the title
    icon     = "/html/img/icons/courier.png", -- optional image url
    color    = "#34C759",         -- optional accent color (hex)
    state    = "active",          -- pending | active | paused | success | failed | canceled
    progress = 0,                 -- optional 0-100
    duration = 300,               -- optional countdown in seconds (preferred on client)
    timeout  = 330000,            -- optional lifetime in ms before auto-expiry
    peek     = true,              -- optional, keeps the island visible after the phone closes
    action   = {                  -- optional button
        label = "Open",
        event = "myresource:openDelivery", -- client event triggered on press
        data  = { id = 1234 },             -- payload for that event
        route = "/courier/"                -- optional, opens the phone at this route
    }
}

exports["gksphone"]:StartLiveActivity(activity) -- returns true, or false if the phone is off/unset (cached and shown later)
```

#### UpdateLiveActivity <a href="#updateliveactivity" id="updateliveactivity"></a>

```lua
--- Only the supplied fields change. An unknown id is started instead of dropped.
exports["gksphone"]:UpdateLiveActivity("delivery:1234", { progress = 60, subtitle = "2 stops left" })
```

#### EndLiveActivity <a href="#endliveactivity" id="endliveactivity"></a>

```lua
--- @param state string|nil success | failed | canceled -- the card lingers briefly to show the outcome
--- @param opts  table|nil  { subtitle = string, immediate = boolean }
exports["gksphone"]:EndLiveActivity("delivery:1234", "success", { subtitle = "Delivered" })
exports["gksphone"]:EndLiveActivity("delivery:1234", "canceled", { immediate = true })
```

#### GetLiveActivity <a href="#getliveactivity" id="getliveactivity"></a>

```lua
local activity = exports["gksphone"]:GetLiveActivity("delivery:1234") -- table | nil
```

#### ClearLiveActivities <a href="#clearliveactivities" id="clearliveactivities"></a>

```lua
exports["gksphone"]:ClearLiveActivities()
```

#### ResyncLiveActivities <a href="#resyncliveactivities" id="resyncliveactivities"></a>

```lua
--- Re-sends every cached activity to the UI. Call after the phone UI reloads.
exports["gksphone"]:ResyncLiveActivities()
```

#### Full example <a href="#full-example" id="full-example"></a>

```lua
local id = "mechanic:" .. plate

exports["gksphone"]:StartLiveActivity({
    id = id,
    app = "mechanic",
    title = "Repair",
    subtitle = "Starting",
    state = "active",
    progress = 0,
    duration = 60,
    peek = true
})

CreateThread(function()
    for step = 1, 60 do
        Wait(1000)
        if not exports["gksphone"]:GetLiveActivity(id) then return end
        exports["gksphone"]:UpdateLiveActivity(id, { progress = math.floor(step / 60 * 100) })
    end
    exports["gksphone"]:EndLiveActivity(id, "success", { subtitle = "Repair complete" })
end)
```

Screen Damage

```lua
local health = exports["gksphone"]:GetScreenHealth()      -- number
local severity = exports["gksphone"]:GetScreenSeverity()  -- none | light | medium | heavy
local wet = exports["gksphone"]:IsPhoneWaterDamaged()     -- boolean

local condition = exports["gksphone"]:GetScreenCondition()
-- { health, severity, waterDamage, damaged }

--- Starts a repair for the local player. Shows a Live Activity card for
--- Config.ScreenDamage.Repair.Duration, then asks the server.
--- The outcome arrives on gksphone:client:screenRepairResult
exports["gksphone"]:RepairPhoneScreen(targetSource) -- targetSource optional

--- Asks the server to resend health. Call after the phone item is equipped.
exports["gksphone"]:RefreshScreenHealth()
```

## Phone Health

```lua
local battery = exports["gksphone"]:GetBatteryHealth()       -- number
local condition = exports["gksphone"]:GetBatteryCondition()  -- good | fair | poor | service

local health = exports["gksphone"]:GetPhoneHealth()
-- { batteryHealth, batteryCondition, chargeCycles }

--- Drain rate scaling from battery wear: 1.0 at full health, rising toward
--- Config.PhoneHealth.Battery.DrainScaling.MaxMultiplier
local multiplier = exports["gksphone"]:GetBatteryDrainMultiplier()      -- number
local interval = exports["gksphone"]:GetBatteryDrainInterval(60000)     -- base ms, scaled by wear

--- Asks the server to replace the battery. The outcome arrives on
--- gksphone:client:batteryReplaceResult
exports["gksphone"]:ReplacePhoneBattery(targetSource) -- targetSource optional

--- Asks the server to resend battery health.
exports["gksphone"]:RefreshBatteryHealth()
```

## Phone

### isPhoneOpen

```lua
local isPhoneOpen = exports["gksphone"]:isPhoneOpen()
print(isPhoneOpen) -- true / false
```

### PhoneOpen

In order for the phone to be open, a player must first open it from the inventory.

```lua
exports["gksphone"]:PhoneOpen()
```

### PhoneClose

```lua
exports["gksphone"]:PhoneClose()
```

### PhoneOpenBlock

Prevent the phone from turning on

```lua
local reason = "Phone cannot be used while handcuffed"
exports["gksphone"]:PhoneOpenBlock(reason)
```

### PhoneOpenUnBlock

If you have blocked the phone from turning on, you can activate it again with this export.

```lua
exports["gksphone"]:PhoneOpenUnBlock()
```

### PhoneOpenBlockStatus

```lua
local status, reason = exports["gksphone"]:PhoneOpenBlockStatus()
print(status, reason) -- true/false, reason
```

### PhoneNumber

```lua
local phoneNumber = exports["gksphone"]:PhoneNumber()
print(phoneNumber) -- nil or 5555555
```

### PhoneUniqueId

```lua
local phoneUniqId = exports["gksphone"]:PhoneUniqueId()
print(phoneUniqId) -- GKS2222222
```

### Is Camera Open

```lua
local isCameraOpen = exports["gksphone"]:IsCameraOpen()
print(isCameraOpen) -- true or false
```

## Services

### Send Report

```lua
local reportMessage = "Report Message"
local reportPhoto = "Image Link" or nil
local job = "ambulance" -- job code
local anonymous = false -- or true

exports["gksphone"]:SendReport(reportMessage, reportPhoto, job, anonymous)
```

## Battery

### GetPhoneBattery

```lua
local battery = exports["gksphone"]:GetPhoneBattery()
print(battery) -- The battery percentage, 0-100
```

### SetPhoneBattery

```lua
local battery = 100 -- The battery percentage, 0-100
exports["gksphone"]:SetPhoneBattery(battery)
```

### SavePhoneBattery

```lua
local battery = 100 -- The battery percentage, 0-100
exports["gksphone"]:SavePhoneBattery(battery)
```

### ToggleCharging

```lua
local charging = true -- true or false
exports["gksphone"]:ToggleCharging(charging)
```

### IsPhoneBatteryDead

```lua
local isBatteryDead = exports["gksphone"]:IsPhoneBatteryDead()
print(isBatteryDead) -- true or false / If the phone has 0% battery
```

### IsPhoneCharging

```lua
local isCharging = exports["gksphone"]:IsPhoneCharging()
print(isCharging) -- true or false
```

## Signal

You must enable Config.Signal (`gksphone/config/signal/config.lua`) to use Export. **Signal requires** [**polyzone**](https://github.com/mkafrin/PolyZone/releases)

### addSignal

```lua
local coord = vec3(-1378.91, -74.53, 51.29) -- v3
local radius = 5
local signalId = exports["gksphone"]:addSignal(coord, radius)
print(signalId) -- This information is required to remove the region.
```

### destroySignal

```lua
exports["gksphone"]:destroySignal(signalId)
```

## Map/GPS

### AddMapLocation

```lua
exports['gksphone']:AddMapLocation({ id = 'biz_1', position = vector2(x, y), name = '24/7', description = 'Open' })
```

### RemoveMapLocation

```lua
exports['gksphone']:RemoveMapLocation('biz_1')
```

### UpdateMapLocation

```lua
exports['gksphone']:UpdateMapLocation('biz_1', { position = vector2(x, y) })
```

## Misc

### heavyJammer

This export renders the phone unusable and only a message section appears in the middle of the screen.

```lua
local status = true -- true or false
local message = "The message you want to write on the screen"
local phoneUniqueId = "GKS22222" -- No Required
exports["gksphone"]:heavyJammer(status, message, phoneUniqueId)

-- Jam local player's phone (non-persistent, client-side only)
exports['gksphone']:heavyJammer(true, "No signal")

-- Jam a specific phone (persistent)
exports['gksphone']:heavyJammer(true, "Signal blocked", "TARGET_PHONE_ID")
```

### ToogleFocus

```lua
local status = true -- true or false
exports["gksphone"]:ToggleFocus(status)
```
