> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nonefivem.com/llms.txt
> Use this file to discover all available pages before exploring further.

# LB Phone

> Integrate NoCloud storage with lb-phone for media uploads.

## Overview

This guide walks you through integrating NoCloud storage with **lb-phone** so that all image, video, and audio uploads go through NoCloud's API.

There are **5 steps** to complete the integration:

1. Change the upload method to `Custom`
2. Whitelist the NoCloud domain
3. Set your NoCloud API keys
4. Add the `GetPresignedUrl` server function
5. Update the `UploadMethods` table

***

## Step 1: Change Upload Method

Edit `lb-phone/config.lua` and find the `Config.UploadMethod` section. Change **all** values to `"Custom"`:

```lua theme={null}
Config.UploadMethod.Video = "Custom"  -- was "Fivemanage"
Config.UploadMethod.Image = "Custom"  -- was "Fivemanage"
Config.UploadMethod.Audio = "Custom"  -- was "Fivemanage"
```

This tells lb-phone to use the custom upload method defined in `shared/upload.lua`.

***

## Step 2: Whitelist NoCloud Domain

In the same `lb-phone/config.lua` file, find `Config.UploadWhitelistedDomains` and add `"nonefivem.com"` to the list:

```lua theme={null}
Config.UploadWhitelistedDomains = {
    "fivemanage.com",
    "fmfile.com",
    "cfx.re",
    "nonefivem.com"  -- ADD THIS LINE
}
```

This allows NoCloud URLs to be displayed inside the phone UI.

***

## Step 3: Set Your NoCloud API Keys

Open `lb-phone/server/apiKeys.lua` and replace the API keys with your NoCloud API keys:

```lua theme={null}
API_KEYS = {
    Video = "API_KEY_HERE",
    Image = "API_KEY_HERE",
    Audio = "API_KEY_HERE",
}
```

Replace each `"API_KEY_HERE"` with your actual NoCloud API key. You can find your API key in the [NoCloud Dashboard](https://dash.nonefivem.com).

***

## Step 4: Add the `GetPresignedUrl` Function

Open `lb-phone/server/custom/functions/functions.lua` and replace the following function. It fetches a signed upload URL from the NoCloud API:

```lua theme={null}
---@param source number
---@param uploadType "Audio" | "Image" | "Video"
---@return string? presignedUrl
function GetPresignedUrl(source, uploadType)
    local apiKey = API_KEYS[uploadType]
    assert(type(apiKey) == "string", "API key for upload type '" .. uploadType .. "' is not defined in API_KEYS.")

    local p = promise.new()

    PerformHttpRequest("https://api.nonefivem.com/cloud/storage/signed-url",
        function(status, responseText, responseHeaders)
            if status == 200 then
                local data = json.decode(responseText)
                p:resolve(data.url)
            else
                print("Failed to get presigned URL. Response code: " .. status)
                p:resolve(nil)
            end
        end, "GET", {
            Authorization = string.format("Bearer %s", apiKey)
        })

    local url = Citizen.Await(p)

    assert(type(url) == "string", "Failed to retrieve a valid presigned URL.")

    return url
end
```

***

## Step 5: Update `UploadMethods`

Open `lb-phone/shared/upload.lua` and **replace** the existing `UploadMethods` table with the one below. The `Custom` entry is configured to work with NoCloud's presigned URLs:

```lua theme={null}
---@class UploadMethod
---@field url string # The url to upload to. Can use BASE_URL & PRESIGNED_URL as well.
---@field field string # The field name (formData)
---@field headers? table<string, any>
---@field error? { path: string, value: any } # The path to the error value and the value to check for
---@field success { path: string } # The path to the video file
---@field suffix? string # Add a suffix to the url? Needed if the url doesn't return the correct file name
---@field sendPlayer? string # The formData field name to send player's metadata to, as json
---@field sendResource? boolean # Send the resource name in the formData?

---@type table<string, { Default: UploadMethod?, Video?: UploadMethod, Image?: UploadMethod, Audio?: UploadMethod }>
UploadMethods = {
    Custom = {
        Default = {
            url = "PRESIGNED_URL",
            field = "file",
            success = {
                path = "url"
            },
            sendPlayer = "metadata"
        },
    },
    Fivemanage = {
        Default = {
            url = "PRESIGNED_URL",
            field = "file",
            success = {
                path = "data.url"
            },
            sendPlayer = "metadata"
        },
    },
    LBUpload = {
        Default = {
            url = "https://BASE_URL/lb-upload/",
            field = "file",
            headers = {
                ["Authorization"] = "API_KEY"
            },
            error = {
                path = "success",
                value = false
            },
            success = {
                path = "link"
            },
            sendPlayer = "metadata"
        },
    },
    OldFivemanage = {
        Video = {
            url = "https://fmapi.net/api/v2/video",
            field = "file",
            headers = {
                ["Authorization"] = "API_KEY"
            },
            success = {
                path = "data.url"
            },
        },
        Image = {
            url = "https://fmapi.net/api/v2/image",
            field = "file",
            headers = {
                ["Authorization"] = "API_KEY"
            },
            success = {
                path = "data.url"
            }
        },
        Audio = {
            url = "https://fmapi.net/api/v2/audio",
            field = "file",
            headers = {
                ["Authorization"] = "API_KEY"
            },
            success = {
                path = "data.url"
            }
        },
    },
}
```

***

## Done

After completing all 5 steps, restart your server. All media uploads from lb-phone (photos, videos, and audio) will now go through NoCloud storage.
