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

# Phone (cc\_phone)

A smartphone item with 28 apps. Photos, videos and voice memos are stored on your own game server – no external image host needed.

**Frameworks:** ESX Legacy, QBCore, QBox

## Features

* Lock screen with passcode, home screen with pages and dock, control centre, notification centre, app switcher, light/dark mode
* Phone, contacts, voicemail and video calls
* Messages, mail, camera, photos and voice memos
* Social apps: Birdy, InstaPic, Trendy, Spark, Pages, Marketplace and Darkchat
* Wallet, crypto and a bills app
* Garage app with valet delivery, Home app for doors/properties
* Maps, services, weather, music, notes, calculator, clock
* Battery with charging in vehicles and power banks; airplane mode; water damage
* Media stored on the game server with a quota per phone number

## How it works

The phone is an **item**. On first use the server assigns a number. All data belongs to the **number**, not to the character – whoever holds the device has its data (except the passcode). With several phones, the last one used is equipped; giving it away unequips it immediately.

The phone is unavailable while down (`ccDown`), cuffed (`ccCuffed`), in water or with an empty battery. In airplane mode only offline apps work.

{% hint style="info" %}
The code is protected by Cfx asset escrow. `config/config.lua`, `config/music.lua`, `locales/*.json`, `shared/cc_framework.lua` and `shared/cc_vehicles.lua` stay editable.
{% endhint %}

## Works well with

* cc\_inventory/00%20Overview\.md) – required, the phone is an item
* cc\_garage/00%20Overview\.md) – valet delivery
* cc\_keys/00%20Overview\.md) – lock/unlock from the Garage app
* cc\_billing/00%20Overview\.md) – Bills app
* cc\_banking/00%20Overview\.md) – bank account in Wallet
* cc\_dispatch/00%20Overview\.md) – companies in Services, duty info in Maps
* cc\_doorlock/00%20Overview\.md) – own doors in the Home app
* cc\_lib/00%20Overview\.md) – shared notifications and dialogs

## Pages

* Installation
* Configuration
* API
* FAQ

## Installation

See also the general installation guide, dependencies and the framework bridge.

### Requirements

| Resource                               | Required | Notes                                                         |
| -------------------------------------- | -------- | ------------------------------------------------------------- |
| `oxmysql`                              | yes      | declared as `dependency`                                      |
| `es_extended`, `qb-core` or `qbx_core` | yes      | one framework                                                 |
| FXServer with **Node 22**              | yes      | `node_version '22'` is needed for the media store             |
| `cc_inventory`                         | yes      | the phone is an item (see `Config.Item.required`)             |
| `pma-voice`                            | optional | call channel and speakerphone; built-in FiveM voice otherwise |
| `cc_dispatch`                          | optional | companies in Services, duty info in Maps                      |
| `cc_banking`                           | optional | bank account in Wallet                                        |
| `cc_billing`                           | optional | Bills app (shows "offline" otherwise)                         |
| `cc_garage`                            | optional | valet delivery                                                |
| `cc_keys`                              | optional | lock/unlock from the Garage app                               |
| `cc_doorlock`                          | optional | own doors in the Home app                                     |
| `cc_lib`                               | optional | shared notifications/dialogs                                  |

`screenshot-basic` is **not** required – the camera captures inside the phone.

### 1. Copy the resource

Copy the folder to `resources/[crankchaos]/cc_phone`.

### 2. Phone item

`cc_inventory/data/items.lua` must contain the item `phone` (not stackable, `server = { export = 'cc_phone.useItem' }`). cc\_inventory ships with this entry.

For a charger item, add an item with `server = { export = 'cc_phone.usePowerbank' }`.

### 3. server.cfg

```cfg
ensure oxmysql
ensure es_extended      # or qb-core / qbx_core
ensure cc_lib           # optional
ensure cc_inventory
ensure pma-voice        # optional
ensure cc_phone
```

### 4. ACE permissions

```cfg
add_ace group.admin cc_phone.admin allow   # /phoneadmin
```

### 5. Database

No SQL file. All tables (`cc_phone_*`) create themselves on start.

### 6. Media folder

{% hint style="danger" %}
`cc_phone/media/` holds player data (photos, videos, voice memos). **Never delete it** when updating and include it in your backups.
{% endhint %}

### Framework notes

No framework-specific steps. The framework is handled through the framework bridge.

## Configuration

Options live in `config/config.lua` (shared by client and server – the server always decides) and `config/music.lua`.

### Controls and item

```lua
Config.Key = 'F1'
Config.Command = 'phone'
Config.FocusKey = 'LMENU'   -- left Alt, toggles the mouse while open
Config.Item = { name = 'phone', required = true }
```

{% hint style="warning" %}
`Config.Item.required = false` is meant for test servers only: every character then gets a bound phone without cc\_inventory.
{% endhint %}

`Config.Prop` and `Config.Anims` define the phone prop and the animations on foot and in vehicles.

### Look

```lua
Config.UI = { theme = 'default', primary = '#8B5CF6', radius = 'md', scale = 1.0, locale = 'de', animations = true, blur = false, sounds = true }
```

### Phone numbers

```lua
Config.NumberFormat = '555-XXXX'
Config.ReservedNumbers = { ['555-0000'] = true, ['555-0911'] = true, ['555-0112'] = true }
```

`X` is a digit. `555-XXXX` yields only 10,000 numbers; for larger servers use e.g. `'55X-XXXX'` **before** numbers are assigned.

### Apps

```lua
Config.Apps = {
    { id = 'phone', default = true, removable = false, size = 42 },
    ...
    { id = 'darkchat', default = false, removable = true, size = 8 },
}
Config.Dock = { 'phone', 'messages', 'camera', 'photos' }
```

* `default` – installed on a new phone; others are installed from the App Store.
* `removable` – whether the player may uninstall it.
* `Config.OfflineApps` – apps that work in airplane mode.

Available app IDs: `phone`, `messages`, `facetime`, `camera`, `photos`, `settings`, `store`, `clock`, `mail`, `weather`, `wallet`, `billing`, `garage`, `home`, `maps`, `notes`, `calculator`, `voicememos`, `services`, `music`, `marketplace`, `pages`, `trendy`, `spark`, `instapic`, `birdy`, `crypto`, `darkchat`.

### Limits and passcode

```lua
Config.Limits = { perSecond = 12, notifications = 100, nameLength = 32 }
Config.Pin = { minLength = 4, maxLength = 6, maxTries = 5, lockSeconds = 300 }
```

The passcode is stored hashed; 5 wrong attempts lock the phone for 5 minutes.

### Battery

```lua
Config.Battery = { enabled = true, drainOpen = 0.8, drainIdle = 0.08, chargeVehicle = 4.0, powerbank = 60, saveEvery = 300 }
```

### Media

```lua
Config.Media = {
    BaseUrl = nil,
    maxBytes = { photo = 600 * 1024, video = 8 * 1024 * 1024, audio = 1024 * 1024 },
    quota = 150 * 1024 * 1024,   -- per phone number
    chunkBytes = 192 * 1024,
    uploadBps = 400000, downloadBps = 600000,
    sessionTimeout = 120,
}
```

Files are stored in `cc_phone/media/` and validated by content (WebP, WebM, Ogg), size and quota. If you serve the folder through an HTTPS proxy, set `BaseUrl`.

### Calls

```lua
Config.Calls = { ringSeconds = 25, voicemailSeconds = 30, channelOffset = 5000 }
Config.RTC = { iceServers = { { urls = 'stun:stun.l.google.com:19302' } } }
Config.Camera = { videoSeconds = 30, maxZoom = 4.0, ... }
```

With pma-voice, calls use a call channel with speakerphone (players within 3 m listen in). Without it, built-in FiveM voice is used and only the two parties hear each other. `Config.RTC` sets the STUN servers for video calls.

### Other options

| Option               | Default                                                   | Meaning                           |
| -------------------- | --------------------------------------------------------- | --------------------------------- |
| `Config.MailDomain`  | `'crankchaos.mail'`                                       | mail address domain               |
| `Config.Blacklist`   | `{}`                                                      | blocked words                     |
| `Config.Services`    | `{}`                                                      | custom service numbers, e.g. taxi |
| `Config.Pages`       | `price = 0, days = 7, maxActive = 5, keepDays = 14`       | Pages ads                         |
| `Config.Marketplace` | `maxActive = 10, maxPrice = 100000000, keepSoldDays = 30` | marketplace listings              |
| `Config.Valet`       | `price = 250`                                             | valet delivery price              |
| `Config.Wet`         | `seconds = 15, chance = 75, battery = 20, cooldown = 60`  | water damage                      |

### Music (`config/music.lua`)

Shipped empty – music belongs to the server owner.

## Exports, Events & Commands

### Commands and keys

| Key / command                                                  | Default   | Permission / effect                                           |
| -------------------------------------------------------------- | --------- | ------------------------------------------------------------- |
| `/phone` (`Config.Command`)                                    | F1        | open/close phone                                              |
| `+cc_phone_cursor`                                             | Left Alt  | toggle mouse while open                                       |
| `+cc_phone_answer`                                             | Enter     | answer call                                                   |
| `+cc_phone_decline`                                            | Backspace | decline call                                                  |
| ESC                                                            | –         | closes the top window, otherwise the phone                    |
| `/phoneadmin verify birdy\|instapic\|trendy <user> 0\|1`       | –         | `cc_phone.admin` – verify an account                          |
| `/phoneadmin password birdy\|instapic\|trendy\|mail <account>` | –         | `cc_phone.admin` – new random password, all phones signed out |

Keys can be changed in the FiveM key bindings.

### Server exports

`target` is a server ID (equipped phone) or a phone number (`'555-1234'`).

| Export                                                                   | Returns / notes          |
| ------------------------------------------------------------------------ | ------------------------ |
| `GetEquippedNumber(src)`                                                 | number                   |
| `GetSourceFromNumber(number)`                                            | server ID                |
| `SendNotification(target, { app, title, content, thumbnail?, open? })`   | –                        |
| `SendMessage(from, to, text, attachments?)`                              | `id` or `nil, error`     |
| `SendCoords(from, to, coords)`                                           | –                        |
| `SendMail({ to, sender, subject, message, attachments?, actions? })`     | `id` or `nil, code`      |
| `GetEmailAddress(number)`                                                | address                  |
| `AddContact(number, contact)`                                            | –                        |
| `CreateCall(src, number, { video? })` / `IsInCall(src)` / `EndCall(src)` | – / `boolean` / –        |
| `AddToGallery(target, mediaId, kind, meta)`                              | –                        |
| `SendCompanyMessage(job, text, coords?)`                                 | recipients               |
| `AddTransaction(number, amount, title)`                                  | –                        |
| `AddCrypto(target, id, amount)` / `RemoveCrypto(target, id, amount)`     | `boolean`                |
| `GetCoin(id)`                                                            | coin                     |
| `PostBirdy(username, content, attachments?)`                             | `boolean`                |
| `RegisterHomeProvider(provider)`                                         | `boolean`                |
| `useItem(src, item)`                                                     | item export for `phone`  |
| `usePowerbank(src)`                                                      | item export for chargers |
| `dryPhone(...)`                                                          | dries a wet phone        |

The JavaScript media exports (`MediaNewId`, `MediaBegin`, `MediaSend`, …) are internal and not meant for third-party use.

```lua
exports.cc_phone:SendNotification(source, { app = 'messages', title = 'Bank', content = 'Salary received' })

exports.cc_phone:SendMail({
    to = '555-1234', sender = 'Maze Bank', subject = 'Invoice', message = 'Please pay.',
    actions = { { label = 'Pay', event = 'myscript:pay', server = true, data = { id = 7 } } },
})
```

#### Home providers

```lua
exports.cc_phone:RegisterHomeProvider({
    name = 'my_housing',
    getHomes = function(src, identifier) return { { id = 12, label = 'Villa', locked = true, owner = true } } end,
    toggleLocked = function(src, identifier, id) return true end,
})
```

Fields: `name` (unique), `getHomes(src, identifier)` (required), `toggleLocked`, `addKeyholder`, `removeKeyholder`, `setWaypoint` (optional). Ownership and distance checks are the provider's job.

### Client exports

`IsOpen()` → `boolean`, `ToggleOpen(open?)`, `IsDisabled()` → `boolean`, `ToggleDisabled(disabled?)` (e.g. jail, cutscene), `GetNumber()`, `SaveToGallery(mediaId)`.

### Public events

| Event                                       | Side   | Payload                         |
| ------------------------------------------- | ------ | ------------------------------- |
| `cc_phone:equipped` / `cc_phone:unequipped` | server | `src, number`                   |
| `cc_phone:message`                          | client | `text`                          |
| mail action `event`                         | server | `(src, data, { number, mail })` |

State bags read: `LocalPlayer.state.ccDown`, `ccCuffed`.

## FAQ & Troubleshooting

**The phone does not open.** The player needs a `phone` item from cc\_inventory/00%20Overview\.md). It is also blocked while down, cuffed, in water or with an empty battery.

**The resource does not start.** cc\_phone needs an FXServer build with Node 22 for the media store.

**Do I need an image host or screenshot-basic?** No. Media is stored in `cc_phone/media/` on your server.

**All photos are gone after an update.** The `media/` folder was deleted or replaced. Always keep it and include it in backups.

**The speaker button is greyed out.** Speakerphone requires `pma-voice`.

**We are running out of phone numbers.** `555-XXXX` allows 10,000 numbers. Change `Config.NumberFormat` (e.g. `'55X-XXXX'`) before numbers are assigned.

**The Home app is empty.** Register a housing provider with `RegisterHomeProvider` or install cc\_doorlock/00%20Overview\.md).

**The Bills app says "offline".** Install cc\_billing/00%20Overview\.md).

**The first incoming call shows up as a notification only.** The call layer loads the first time Phone, Video, Services or a phonebook is opened. Until then, answer with Enter and decline with Backspace.

**The music app is empty.** No music is shipped. Add your own in `config/music.lua`.

**Is `server/media.js` encrypted?** No, JavaScript is not encrypted by escrow.

Still stuck? See Support.


---

# 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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://ccfivem.gitbook.io/ccfivem-docs/player-and-ui/phone-cc_phone.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
