Skip to main content

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":
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:
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:
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.

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:
---@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:
---@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.