Custom Music API
By default, the Music app searches the built-in music library (roadshop_music_library), which is filled through player submissions and the in-app admin panel. With the Custom Music API you can replace that library entirely and serve songs from your own HTTP server — the same server-to-server pattern used by Custom Upload.
How It Works
Server-Side Only
The request runs on the FiveM server via
PerformHttpRequest. Your API key never leaves the server — the NUI frontend never sees your endpoint or credentials.No Frontend Changes
The Music app works exactly as before: search, playlists, and playback are untouched. Only the data source changes.
Unlimited Catalog
Every search hits your server live, so your catalog can be as large as you want — your server does the filtering.
YouTube & Direct Files
Each song can either be a YouTube video id or a direct link to an audio file (mp3/ogg) on your own CDN.
Configuration
EditMusicAPI.lua in the resource root (it is escrow_ignore, so you can edit it freely):
MusicAPI.lua
config.lua changes and no frontend rebuild needed. Restart the resource after changing these values.
Request Format
For every search in the Music app, RoadPhone sends:- The
Authorizationheader is only sent whenMusicAPI.APIKeyis set. - An empty
searchparameter is sent when the player opens the search view. Return your newest or featured songs in that case.
Response Format
Your endpoint must respond with HTTP 200 and a JSON array of songs (RoadPhone uses at most the first 50):{ "songs": [ ... ] }
Song Fields
| Field | Required | Description |
|---|---|---|
id | ✅ | YouTube video id when url_type is youtube, or a full https:// URL to an audio file when url_type is direct |
title | ✅ | Song title shown in the app |
artist | ✅ | Artist name shown in the app |
url_type | ❌ | "youtube" or "direct" — defaults to "youtube" |
thumbnail | ❌ | Cover image URL |
length | ❌ | Song length as mm:ss — defaults to 0:00 |
Songs without an
id or title are skipped. On any error (non-200 status, invalid JSON), the app shows an empty result list and a warning is printed to the FiveM server console.Example: Building Your Own Endpoint
A minimal music API using Node.js and Express:In production, serve the library from a database, add rate limiting, and cache popular queries. Direct audio files must be publicly reachable from every player’s game client (they are streamed via xSound/mx-surround).
Troubleshooting
Search always shows an empty list
Search always shows an empty list
- Check the FiveM server console for
[RoadPhone] MusicAPI ...warnings - Verify your endpoint is reachable from the FiveM server (try
curlon the machine) - Confirm the response is a JSON array (or
{ "songs": [...] }) withidandtitleon every song - Make sure the API key in
MusicAPI.luamatches what your endpoint expects
Songs appear but won't play
Songs appear but won't play
- For
url_type: "youtube",idmust be the plain video id (e.g.dQw4w9WgXcQ), not a full URL - For
url_type: "direct",idmust be a fullhttps://URL to an audio file that players’ game clients can reach - Test a direct URL in your browser — it should download/stream the audio file without a login
The built-in library still shows up
The built-in library still shows up
- Ensure
MusicAPI.Enabled = trueinMusicAPI.lua(resource root, next toAPI.lua) - Restart the resource completely after changing the file
- Check that
MusicAPI.luais listed infxmanifest.luaunderserver_scripts