> For the complete documentation index, see [llms.txt](https://codeforge.gitbook.io/codeforge/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://codeforge.gitbook.io/codeforge/phone/smartphone.md).

# SMARTPHONE

### Overview

Forge Phone replaces legacy phone scripts with a cohesive mobile experience:

* **FORGE OS** — lock screen, home screen, dock, control center, notifications, app store, themes and wallpapers.
* **Real-time communication** — SMS-style messages, group chats, voice calls through **pma-voice**, and optional **WebRTC video calls**.
* **Life simulation** — camera with cloud upload, gallery, email, classified ads, dating, social feeds, and streaming.
* **Economy hooks** — bank transfers, invoices, and a **ByteMe** mobile data system that gates online actions.
* **Underworld & law enforcement** — a retro **burner phone** excluded from wiretap, and a **police tablet** for surveillance dossiers.

Open the phone with the configured key (default **M**), the `/phone` command, or by using the phone item from inventory.

***

### Features

| Feature          | Description                                                                      |
| ---------------- | -------------------------------------------------------------------------------- |
| Voice calls      | Outgoing/incoming calls with history, contact integration, and pma-voice routing |
| Video calls      | WebRTC peer video with STUN/TURN support and in-game cell camera                 |
| Messages         | Direct chats with read state, media, and contact requests                        |
| Contacts         | Full address book synced to the server                                           |
| Camera & Gallery | In-game photos uploaded to FiveManage, stored per character                      |
| App Store        | Install/uninstall downloadable apps defined in `Config.Apps`                     |
| ByteMe (InetMax) | Mobile data balance consumed by calls, posts, transfers, and messages            |
| Bank (Wallet)    | Balance, transfers, and bill payments with framework or ds\_banking              |
| Mail             | Inbox for receipts, ads, and server announcements                                |
| Services         | Ticket threads to police, EMS, taxi, businesses, and more                        |
| Social apps      | Bleeter, Insta, WhatsUP groups, Spark dating, LifeInvader ads                    |
| Play TV          | Video streaming surface inside the phone                                         |
| Burner phone     | Separate disposable device with its own number pool                              |
| Police wiretap   | Tablet UI for GPS, message/call history, live intercept, and dossiers            |
| Signal zones     | Optional dead zones where sending/calling is blocked                             |
| i18n             | English and Spanish locales in the phone UI                                      |
| Themes           | Accent color, wallpaper, and OS personalization in Settings                      |

***

### Apps

#### Pre-installed (System)

These apps ship on every phone and **cannot be uninstalled**:

| ID         | Display name | Purpose                                  |
| ---------- | ------------ | ---------------------------------------- |
| `phone`    | Phone        | Dialer, recent calls, contact requests   |
| `messages` | Messages     | Direct messaging                         |
| `contacts` | Contacts     | Address book                             |
| `camera`   | Camera       | Take photos in-world                     |
| `settings` | Settings     | Theme, wallpaper, notifications, privacy |
| `appstore` | App Store    | Browse and manage downloadable apps      |
| `gallery`  | Photos       | Photo library                            |

#### Downloadable (App Store)

Users install these from the App Store. Only IDs listed in `Config.Apps.Downloadable` are available:

| ID          | Display name | Category      | Description                         |
| ----------- | ------------ | ------------- | ----------------------------------- |
| `wallet`    | Bank         | Finance       | Balance, transfers, bills           |
| `email`     | Mail         | Productivity  | Character inbox                     |
| `services`  | Services     | Utilities     | Contact jobs and emergency services |
| `loops`     | Bleeter      | Social        | Twitter-style posts and comments    |
| `ads`       | Ads          | Utilities     | Classified listings with photos     |
| `inetmax`   | ByteMe       | Utilities     | Top up and monitor mobile data      |
| `playtv`    | Play TV      | Entertainment | Stream videos on the go             |
| `lovy`      | Spark        | Social        | Dating / swipe profiles             |
| `snapmatic` | Insta        | Social        | Photo feed, likes, comments         |
| `whatsup`   | WhatsUP      | Social        | Group chat rooms                    |

To change which apps are system vs downloadable, edit `Config.Apps` in `config/config.lua`.

***

### Requirements

Start dependencies **before** `forge-phone`:

```cfg
ensure ox_lib
ensure oxmysql
ensure screenshot-basic
ensure pma-voice
ensure forge-phone
```

| Dependency                                                        | Role                                    |
| ----------------------------------------------------------------- | --------------------------------------- |
| [ox\_lib](https://github.com/overextended/ox_lib)                 | Callbacks, UI helpers, shared utilities |
| [oxmysql](https://github.com/overextended/oxmysql)                | Database queries and migrations         |
| [screenshot-basic](https://github.com/citizenfx/screenshot-basic) | Camera capture pipeline                 |
| [pma-voice](https://github.com/AvarianKnight/pma-voice)           | Voice calls and wiretap audio bridge    |

**Optional integrations**

* **FiveManage** — photo upload API (see Camera & Photo Upload)
* **ds\_banking** — external banking when `Config.Banking.Resource = 'auto'`
* **MugShotBase64** — live mugshots on the wiretap tablet
* **interact-sound** — ring tones (customize in `config/open_functions.lua`)

If your server uses another voice resource, override `ForgePhone.JoinVoiceCall`, `ForgePhone.LeaveVoiceCall`, and the wiretap voice helpers in `config/open_functions.lua`.

***

### Installation

#### 1. Add the resource

Place the folder in your resources directory as `forge-phone` and ensure it in `server.cfg` after the dependencies.

#### 2. Set your framework

In `config/config.lua`:

```lua
Config.Core = "QBX" -- "QB", "QBX" or "ESX"
```

#### 3. Configure item names

```lua
Config.PhoneItem = 'phone'
Config.Burner.Item = 'burner_phone'
```

#### 4. Register inventory items

Add the phone and burner items to your inventory system (see Inventory Items).

#### 5. Database

On first start, Forge Phone creates and migrates its database tables automatically.

If your host blocks automatic DDL, import `forge-phone.sql` manually before starting the resource.

#### 6. FiveManage API key

Add your media API key to `server.cfg` **before** the resource starts:

```cfg
set FIVEMANAGE_MEDIA_API_KEY "your_fivemanage_media_api_key"
```

Never expose the API key outside `server.cfg` (no public configs, screenshots, or shared paste links).

#### 7. Optional bridges

Adjust hooks in:

* `config/open_functions.lua` — sounds, voice, mugshots
* `config/bridge_client.lua` — client framework bridge
* `config/bridge_server.lua` — server framework bridge, money, jobs, items

***

### Inventory Items

The normal phone opens with `forge-phone:client:open`.\
The burner opens with `forge-phone:client:openBurner`.

Use **non-consumable** items. The script verifies the player still has the item before opening and while burner call state is active.

#### ox\_inventory

Add to `ox_inventory/data/items.lua`:

```lua
['phone'] = {
    label = 'Phone',
    weight = 300,
    stack = false,
    close = true,
    consume = 0,
    client = {
        event = 'forge-phone:client:open',
    },
    description = 'Forge smartphone',
},

['burner_phone'] = {
    label = 'Burner Phone',
    weight = 250,
    stack = false,
    close = true,
    consume = 0,
    client = {
        event = 'forge-phone:client:openBurner',
    },
    description = 'Disposable phone',
},
```

#### QBCore / qb-inventory

Add to `qb-core/shared/items.lua`:

```lua
['phone'] = {
    name = 'phone',
    label = 'Phone',
    weight = 300,
    type = 'item',
    image = 'phone.png',
    unique = true,
    useable = true,
    shouldClose = true,
    combinable = nil,
    description = 'Forge smartphone',
},

['burner_phone'] = {
    name = 'burner_phone',
    label = 'Burner Phone',
    weight = 250,
    type = 'item',
    image = 'burner_phone.png',
    unique = true,
    useable = true,
    shouldClose = true,
    combinable = nil,
    description = 'Disposable phone',
},
```

Register usable callbacks server-side (after `qb-core` loads):

```lua
local QBCore = exports['qb-core']:GetCoreObject()

QBCore.Functions.CreateUseableItem('phone', function(source, item)
    local Player = QBCore.Functions.GetPlayer(source)
    if not Player or not Player.Functions.GetItemByName(item.name) then return end
    TriggerClientEvent('forge-phone:client:open', source)
end)

QBCore.Functions.CreateUseableItem('burner_phone', function(source, item)
    local Player = QBCore.Functions.GetPlayer(source)
    if not Player or not Player.Functions.GetItemByName(item.name) then return end
    TriggerClientEvent('forge-phone:client:openBurner', source)
end)
```

#### QBX / qbx\_core

If you use QBX with `ox_inventory`, use the ox\_inventory definitions above.

Otherwise:

```lua
exports.qbx_core:CreateUseableItem('phone', function(source)
    TriggerClientEvent('forge-phone:client:open', source)
end)

exports.qbx_core:CreateUseableItem('burner_phone', function(source)
    TriggerClientEvent('forge-phone:client:openBurner', source)
end)
```

#### ESX

SQL for the legacy `items` table:

```sql
INSERT INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
    ('phone', 'Phone', 300, 0, 1),
    ('burner_phone', 'Burner Phone', 250, 0, 1)
ON DUPLICATE KEY UPDATE
    `label` = VALUES(`label`),
    `weight` = VALUES(`weight`);
```

If your table only has `name`, `label`, and `weight`, remove `rare` and `can_remove`.

Server callbacks:

```lua
ESX.RegisterUsableItem('phone', function(source)
    TriggerClientEvent('forge-phone:client:open', source)
end)

ESX.RegisterUsableItem('burner_phone', function(source)
    TriggerClientEvent('forge-phone:client:openBurner', source)
end)
```

#### qs-inventory

Add to `qs-inventory/shared/items.lua`:

```lua
['phone'] = {
    ['name'] = 'phone',
    ['label'] = 'Phone',
    ['weight'] = 300,
    ['type'] = 'item',
    ['image'] = 'phone.png',
    ['unique'] = true,
    ['useable'] = true,
    ['shouldClose'] = true,
    ['combinable'] = nil,
    ['description'] = 'Forge smartphone',
},

['burner_phone'] = {
    ['name'] = 'burner_phone',
    ['label'] = 'Burner Phone',
    ['weight'] = 250,
    ['type'] = 'item',
    ['image'] = 'burner_phone.png',
    ['unique'] = true,
    ['useable'] = true,
    ['shouldClose'] = true,
    ['combinable'] = nil,
    ['description'] = 'Disposable phone',
},
```

QS setups based on QBCore still need the `CreateUseableItem` callbacks unless your QS version binds its own client events.

***

### Configuration

All customization is done through these files:

```
config/config.lua          — core settings, apps, wiretap, video, signal, services
config/vehicles.lua        — vehicle-related helpers
config/open_functions.lua  — voice, sounds, mugshots (client hooks)
config/bridge_client.lua   — framework client bridge
config/bridge_server.lua   — framework server bridge
config/logs_server.lua     — server logging hooks
```

#### Essential settings

```lua
Config.Core = "QBX"
Config.OpenPhone = 'M'
Config.PhoneItem = 'phone'
Config.AllowWalkingWhilePhoneOpen = true

Config.Burner.Enabled = true
Config.Burner.Item = 'burner_phone'
Config.Burner.Command = 'burnerphone'
```

#### App catalog

```lua
Config.Apps = {
    System = {
        'phone', 'messages', 'contacts', 'camera',
        'settings', 'appstore', 'gallery',
    },
    Downloadable = {
        'email', 'wallet', 'services', 'loops', 'ads',
        'inetmax', 'playtv', 'lovy', 'snapmatic', 'whatsup',
    },
}
```

Only apps listed in `Config.Apps.System` or `Config.Apps.Downloadable` can be installed or removed.

#### Call settings

```lua
Config.RepeatTimeout = 3000   -- ms between ring tones
Config.CallRepeats = 5        -- rings before missed call
```

#### Notification texts

Customize player-facing strings in `Config.Texts` and per-feature `Texts` tables (burner, wiretap, etc.).

***

### Burner Phone

The burner is a **separate disposable device** with a retro UI and its own number table. It is intentionally **excluded from police wiretap and tracking**.

| Setting                            | Default        | Notes                         |
| ---------------------------------- | -------------- | ----------------------------- |
| `Config.Burner.Enabled`            | `true`         | Master switch                 |
| `Config.Burner.Item`               | `burner_phone` | Inventory item                |
| `Config.Burner.Command`            | `burnerphone`  | Opens without item if enabled |
| `Config.Burner.AllowIncomingCalls` | `true`         | Incoming burner calls         |
| `Config.Burner.NumberMin/Max`      | `1000`–`9999`  | Short number pool             |

Features toggled under `Config.Burner.Features`: outgoing calls, contacts, settings.

**Behaviour highlights**

* Cannot open the main phone and burner at the same time during active calls.
* Uses prop model `npds_oldphone_base` (see Props).
* Numbers are stored separately from the main phone profile.

***

### Police Wiretap Tablet

Judicial surveillance tool for configured police jobs. Open with `/poltablet` (configurable).

```lua
Config.Wiretap = {
    Enabled = true,
    Command = 'poltablet',
    Jobs = {
        ['police'] = 0,
        ['sheriff'] = 0,
    },
    MaxSessionsPerOfficer = 1,
    LocationUpdateIntervalMs = 2000,
    JoinVoiceOnActiveCall = true,
    Features = {
        HistoricalMessages = true,
        HistoricalCalls = true,
        HistoricalSocialActivity = true,
        LiveMessages = true,
        LiveCallAudio = true,
        LocationTracking = true,
        PortraitCapture = true,
    },
}
```

#### What officers can do

* **Target dossiers** — save suspects with labels (suspect, witness, victim, etc.), notes, and display names.
* **GPS tracking** — live map with periodic position updates from the target client.
* **Message history** — SMS and service threads linked to the target number.
* **Call history** — past call metadata.
* **Live intercept** — real-time messages while a wiretap session is active.
* **Live call audio** — when enabled, the officer joins the target's pma-voice call in listen-only mode.
* **Portrait** — mugshot from DB avatar, optional MugShotBase64 resource, or native capture.

#### Limits

* Burner phones are **never** wiretappable.
* `MaxSessionsPerOfficer` prevents abuse.
* History rows are capped by `Config.Wiretap.HistoryLimits`.

Preset labels: `suspect`, `witness`, `victim`, `person_of_interest`, `accomplice`, `informant`, `other`.

***

### Video Calls

WebRTC video calls run between two players in an active phone call.

```lua
Config.VideoCall = {
    Enabled = true,
    STUNServers = {
        "stun:stun1.l.google.com:19302",
        "stun:stun2.l.google.com:19302",
    },
    TURNServers = {}, -- add your TURN credentials for strict NAT
    InetMaxUsage = math.random(300000, 800000),
}
```

**Requirements**

* `Config.VideoCall.Enabled = true`
* Both players need sufficient **ByteMe** data when InetMax is enabled.
* pma-voice handles call audio; video uses WebRTC with the STUN/TURN settings below.

For production servers behind strict firewalls, configure **TURN** servers in `TURNServers`. Google STUN alone is enough for many home networks but not all datacenter setups.

***

### ByteMe — Mobile Data

**ByteMe** (`inetmax` app) is Forge Phone's mobile data economy. When `Config.App.InetMax.IsUseInetMax = true`, online actions consume KB from the character balance.

#### Top-up

```lua
Config.App.InetMax.TopupRate = {
    InKB = 1000000,  -- 1 GB per unit
    Price = 100,     -- price per unit
}
Config.App.InetMax.SocietySeller = "government"
```

#### Usage examples (randomized ranges in KB)

| Action                 | Config key                           |
| ---------------------- | ------------------------------------ |
| Send message           | `MessageSend`                        |
| Bleeter post / comment | `LoopsPostTweet`, `LoopsPostComment` |
| Insta post / comment   | `SnapmaticPost`, `SnapmaticComment`  |
| Ads post               | `AdsPost`                            |
| Voice call             | `PhoneCall`                          |
| Video call             | `Config.VideoCall.InetMaxUsage`      |
| Bank transfer          | `BankTransfer`                       |
| Service message        | `ServicesMessage`                    |

If the balance is too low, players see `Config.MsgNotEnoughInternetData` and the action is blocked.

***

### Camera & Photo Upload

Photos are captured through `screenshot-basic` and uploaded to **FiveManage**:

```lua
Config.PhotoUpload = {
    provider = 'fivemanage',
    endpoint = 'https://api.fivemanage.com/api/v3/file/base64',
    timeout = 10000,
    encoding = 'webp',
    quality = 0.85,
    path = 'forge-phone/photos',
}
```

**server.cfg**

```cfg
set FIVEMANAGE_MEDIA_API_KEY "your_fivemanage_media_api_key"
```

Saved URLs are stored in the gallery and can be used in Bleeter, Insta, Ads, Spark, and profile avatars.

***

### Banking & Wallet

```lua
Config.Banking = {
    Resource = 'auto', -- auto, framework, ds_banking
    AutoDetect = { 'ds_banking' },
}
```

| Mode         | Behaviour                                                    |
| ------------ | ------------------------------------------------------------ |
| `auto`       | Tries listed external banks, falls back to framework account |
| `framework`  | Uses QB/QBX/ESX bank balance only                            |
| `ds_banking` | Forces ds\_banking integration                               |

The Wallet app supports transfers, balance checks, and invoice payments. Top-ups for ByteMe credit the configured society account.

**Admin diagnostic**

`/fpbankdiag` prints banking diagnostics but requires ACE permission `forgephone.bankdiag` (or generic `command` ace).

***

### Signal Zones

Optional coverage simulation. Disabled by default.

```lua
Config.Signal = {
    IsUse = false,
    DefaultSignalZones = "FULL_SIGNAL",
    Zones = {
        ["FULL_SIGNAL"] = {
            CenterCoords = vec3(49.58, -1560.84, 29.38),
            Radius = 3,
            ChanceSignal = 1.0,
        },
        -- add more zones with ChanceSignal 0.0 – 1.0
    },
}
```

When `IsUse = true`, players inside low-signal zones cannot send messages or place calls. Message: `Config.MsgSignalZone` (`"No Signal"`).

***

### Services App

Pre-configured service desks in `Config.Services`. Each entry maps a **job name** to a ticket channel:

| Key          | Job        | Type      |
| ------------ | ---------- | --------- |
| `goverment`  | goverment  | General   |
| `police`     | police     | General   |
| `ambulance`  | ambulance  | Health    |
| `realestate` | realestate | Property  |
| `taxi`       | taxi       | Transport |
| `burgershot` | burgershot | Food      |
| `kfc`        | kfc        | Food      |

Add or rename entries to match your server's jobs. `minGrade` controls which job grade can respond to tickets.

***

### Props & Stream Files

Phone and burner props are streamed from `stream/`:

```
stream/npds_phone_base.ydr      — main smartphone prop
stream/npds_oldphone_base.ydr     — burner phone prop
stream/npds_phone_prop.ytyp     — archetype metadata
```

Manifest entry:

```lua
data_file "DLC_ITYP_REQUEST" "stream/npds_phone_prop.ytyp"
```

| Device       | Model                |
| ------------ | -------------------- |
| Main phone   | `npds_phone_base`    |
| Burner phone | `npds_oldphone_base` |

If a prop appears **grey or untextured**, the drawable loaded but the texture dictionary did not. Add matching `.ytd` files from the NPDS prop package to `stream/` if included, restart the resource, and clear client cache if needed.

These props are created by **Nukepug Designs** — see Special Thanks.

***

### Debug & Troubleshooting

#### Enable debug logs

```lua
Config.Debug = false

Config.DebugScopes = {
    all = true,
    bridge = true,
    camera = true,
    database = true,
    phone = true,
    props = true,
    signal = true,
    web = true,
    wiretap = true,
}
```

Set `Config.Debug = true`. Use `all = false` and enable individual scopes to reduce console noise.

#### Common issues

| Symptom                   | Check                                                                    |
| ------------------------- | ------------------------------------------------------------------------ |
| Phone does not open       | Item registered, `Config.PhoneItem` matches, player has item             |
| No photos / gallery empty | `FIVEMANAGE_MEDIA_API_KEY` in server.cfg, screenshot-basic running       |
| No voice in calls         | pma-voice started, `ForgePhone.JoinVoiceCall` not overridden incorrectly |
| Video call black screen   | TURN servers, firewall, `Config.VideoCall.Enabled`                       |
| Wiretap no GPS            | Target online, tap session active, `LocationTracking` enabled            |
| Database errors           | oxmysql connection, run `forge-phone.sql` manually if DDL blocked        |
| Grey phone prop           | Missing `.ytd` textures in `stream/`                                     |

#### Commands

| Command        | Access                    | Purpose                          |
| -------------- | ------------------------- | -------------------------------- |
| `/phone`       | All                       | Open phone (if item checks pass) |
| `/burnerphone` | All                       | Open burner (if enabled)         |
| `/poltablet`   | Wiretap jobs              | Open police surveillance tablet  |
| `/fpbankdiag`  | ACE `forgephone.bankdiag` | Banking diagnostics              |

***

### Special Thanks

Forge Phone uses community-made props for the in-hand phone models. Huge thanks to **Nukepug Designs (NukePugs)** for creating and sharing high-quality props and scripts for the FiveM community.

|             | Link                                                |
| ----------- | --------------------------------------------------- |
| **Discord** | [Nukepug Design's](https://discord.gg/DXe7vZwN2A)   |
| **GitHub**  | [NukepugDesigns](https://github.com/NukepugDesigns) |

Nukepug Designs publishes prop packs, MLOs, minigames, and more for roleplay servers. If you use Forge Phone props in trailers or showcases, consider crediting **Nukepug Designs** and supporting their work.

**Props used in this resource**

* `npds_phone_base` — main smartphone
* `npds_oldphone_base` — burner phone
* `npds_phone_prop.ytyp` — prop metadata

***

### License & Support

Forge Phone is distributed by **CodeForge**. Refer to your Tebex or purchase page for license terms, updates, and official support channels.

For configuration questions, start with this document and the files under `config/`. Enable scoped debug logging before opening support tickets so staff can diagnose issues quickly.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://codeforge.gitbook.io/codeforge/phone/smartphone.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
