Custom Upload
RoadPhone supports two upload methods: FiveManage (a managed third-party service) and Custom Upload (your own endpoint). This guide explains how to set up and use the Custom Upload method.Why Presigned URLs?
Presigned URLs are the industry-standard approach for secure file uploads. Here’s why RoadPhone enforces this pattern:API Key Security
Your API key never leaves the server. It is only used server-side to request a presigned URL from your storage provider. The NUI frontend (browser) never sees or transmits your credentials.
No Key Leakage
Since the FiveM NUI layer runs in a Chromium browser, any API key sent to the client can be extracted by players using browser developer tools. Presigned URLs eliminate this risk entirely.
Time-Limited Access
Presigned URLs are temporary. Even if intercepted, they expire after a short period and can only be used for a single upload. This limits the blast radius of any potential misuse.
Full Control
You control the storage backend, file size limits, allowed file types, and expiration times — all from your own server.
How It Works
Phone requests upload
The Phone NUI triggers a callback (
requestgfu) to the FiveM server, asking for a presigned URL.FiveM Server contacts your API
The FiveM server sends a
GET request to your upload API endpoint, authenticating with your API key (server-side only).Your API generates a presigned URL
Your API server generates a time-limited presigned URL from your storage provider (S3, R2, etc.) and returns it.
Presigned URL is passed back
The presigned URL travels back through the FiveM server to the Phone NUI — without exposing any API key.
Phone uploads directly to storage
The Phone NUI uploads the file directly to the storage provider using the presigned URL.
Key point: Your API key is only used in step 2 (server-to-server). The NUI client never touches it.
Configuration
Step 1: Set Upload Method
Inconfig.lua, set the upload method to custom:
config.lua
Step 2: Configure Your Endpoint
Edituploader/upload-server.lua with your endpoint details:
uploader/upload-server.lua
fxmanifest.lua as a server script, so no additional setup is needed.
API Response Format
Your presigned URL endpoint must return a JSON response that contains apresignedUrl field. RoadPhone expects the following structure:
Presigned URL Response
Your API endpoint (the one called byupload-server.lua) should return:
The phone extracts the presigned URL from
response.data.presignedUrl. Make sure your API returns this exact structure.Upload Result Response
After the client uploads a file to the presigned URL, the storage service should return the final URL of the uploaded file. RoadPhone supports two common response formats:- Format A (Nested)
- Format B (Flat)
response.data.url first, then falls back to response.url.
Supported File Types
Thefiletype parameter passed to your endpoint indicates what kind of media is being uploaded:
| File Type | Used By | Example MIME Types |
|---|---|---|
image | Camera, Snapy, Livestream, Instagram, Control Centre | image/png, image/jpeg, image/webp |
video | Camera (video recording) | video/webm |
audio | Voice Memos, Voice Messages | audio/webm, audio/mpeg |
Example: Building Your Own Endpoint
Here is a minimal example of a presigned URL API using Node.js and AWS S3:This is a simplified example. In production, add rate limiting, file size validation, and proper error handling.
Troubleshooting
Uploads fail silently
Uploads fail silently
- Check your FiveM server console for errors from
upload-server.lua - Verify your API endpoint is reachable from the FiveM server
- Ensure the API key in
upload-server.luamatches your endpoint’s expected key - Confirm your endpoint returns
{ data: { presignedUrl: "..." } }format
File uploads succeed but URL is empty
File uploads succeed but URL is empty
- Check the response format from your storage provider after upload
- RoadPhone expects either
{ data: { url: "..." } }or{ url: "..." } - Test your presigned URL manually with
curlto see the response format
Config.uploadMethod is set but nothing happens
Config.uploadMethod is set but nothing happens
- Ensure
config.luahasConfig.uploadMethod = 'custom'(not'fivemanage') - Restart the FiveM resource completely after changing the config
- Check that
uploader/upload-server.luais listed infxmanifest.luaunderserver_scripts