Streaming API
How to play RadioMV stations in your app, website, or web service, and how to show now-playing metadata. Everything on this page is public — no API key or registration required.
Quick Start
| I want to… | Use this URL |
|---|---|
| Play a station in an app or browser (HLS, adaptive quality) | https://stream.radiomv.com/stream/{station}.m3u8 |
| Play a station on a simple / hardware MP3 player | http://stream.radiomv.com/stream/{station}.m3u — fetch it, then follow the URL inside |
| Show what's playing right now | https://stream.radiomv.com/api/metadata/{station} |
| Get live now-playing updates (no polling) | https://stream.radiomv.com/api/metadata/{station}/events (SSE) |
Replace {station} with an ID from the station list, e.g.:
/stream/english.m3u8
Base URL & Hostname Rules
Always start from https://stream.radiomv.com. It geo-routes each listener to a nearby server automatically.
stream.radiomv.com contain absolute URLs on *.radiomv.live hosts — that is by design (it sends audio traffic directly to the server nearest the listener). Those hostnames are internal infrastructure: they can change, move, or disappear at any time. Follow them when a playlist hands them to you; never store them in your app, config, or database.
stream.radiomv.com will fetch audio segments from *.radiomv.live. For a web page that means CSP directives like:media-src https://stream.radiomv.com https://*.radiomv.live;connect-src https://stream.radiomv.com https://*.radiomv.live;
HTTPS vs HTTP: use https:// everywhere you can. Plain http:// is deliberately kept working for the audio endpoints (.mp3, .m3u) so embedded and hardware players without TLS support can connect.
Stations
Live Stations
24/7 curated programs and music.
| Station ID | Name | Language |
|---|---|---|
slavic | Slavic | Russian |
slavic-music | Slavic Music | Russian |
slavic-kids | Slavic Kids | Russian |
english | English | English |
spanish | Spanish | Spanish |
german | German | German |
Bible Stations
Continuous audio Bible reading, 24/7.
| Station IDs | Name |
|---|---|
slavic-nt / slavic-ot | Slavic New / Old Testament |
english-nt / english-ot | English New / Old Testament |
spanish-nt / spanish-ot | Spanish New / Old Testament |
german-nt / german-ot | German New / Old Testament |
From an integration standpoint, Bible stations behave exactly like the live stations — same URLs, same players, same metadata API (the title is the current book and chapter). The only difference is that their HLS masters have no ultra quality tier.
GET /api/metadata returns one entry per station — use it to build your station list dynamically instead of hardcoding it.
Option 1 — HLS (Recommended)
HLS is the recommended way to play RadioMV in any modern environment: iOS, Android, web browsers, smart TVs, VLC, ffmpeg. It adapts quality to the listener's bandwidth automatically.
One URL is all you need — the master playlist:
/stream/{station}.m3u8
Give that URL to your player. It discovers the quality variants, picks one, and pulls audio segments on its own.
Quality Tiers
What the master playlist advertises today:
| Variant | Bitrate | Codec |
|---|---|---|
lofi | ~24–32 kbps | HE-AAC v2 |
midfi | 64 kbps | HE-AAC |
hifi | 128 kbps | AAC-LC |
ultra | 248 kbps | AAC-LC |
Bible stations omit the ultra tier. Segments are 6-second fMP4/CMAF (.m4s).
?sid=...) — pass URLs through unmodified, exactly as any standard HLS player already does.
Web Embed (hls.js + Safari)
Safari plays HLS natively; other browsers need hls.js:
<audio id="player" controls></audio>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1"></script>
<script>
const url = "https://stream.radiomv.com/stream/english.m3u8";
const audio = document.getElementById("player");
if (audio.canPlayType("application/vnd.apple.mpegurl")) {
audio.src = url; // Safari / iOS
} else if (Hls.isSupported()) {
const hls = new Hls();
hls.loadSource(url);
hls.attachMedia(audio);
}
</script>
CORS is open (Access-Control-Allow-Origin: *) on all streaming and metadata endpoints, so this works from any web origin.
Option 2 — MP3 (Simple Players & Hardware)
A single fixed-quality 128 kbps MP3 stream, Icecast/SHOUTcast-compatible. Works with anything that can play an MP3 URL: <audio> tags, VLC, Winamp, internet-radio hardware, microcontrollers.
Preferred pattern — resolve, then play:
- Fetch the playlist:
GET
/stream/{station}.m3u - The response body is one line: the direct MP3 stream URL for the server assigned to this listener.
- Connect your player to that URL.
- On every reconnect or new playback session, re-fetch the
.m3ufirst. Never save the resolved URL — it points at one specific server, and a saved URL stops working if that server is replaced. Devices that re-resolve heal automatically; devices that cache the final URL are the ones that end up "connecting forever."
Direct URL (also supported — e.g. for a plain <audio> tag where the playlist indirection is impractical):
/stream/{station}.mp3
ICY (SHOUTcast) Metadata
If your client sends the header Icy-MetaData: 1, the stream interleaves now-playing titles in standard ICY format. The response includes:
icy-name: English
icy-br: 128
icy-metaint: 16000
icy-metaint is the byte interval between metadata blocks. If you don't send Icy-MetaData: 1, you get a clean MP3 stream with no interleaved metadata — use the JSON metadata API instead.
Now-Playing Metadata
JSON, no auth, CORS-open. Titles for Bible stations are the current book and chapter; for live stations, the current track or program.
/api/metadata
Array — now playing on all stations.
/api/metadata/{station}
Object — now playing on one station:
{
"station": "english",
"name": "English",
"title": "The Righteous Requirement of the Law | Clip 1 | Derek Prince",
"artist": "J Scott Rakozy",
"updated_at": 1787445124
}
updated_at is Unix seconds. artist may be empty. Treat unknown extra fields as forward-compatible additions.
/api/metadata/{station}/events
Server-Sent Events stream — holds the connection open and pushes each change as a data: line with the same JSON shape:
const es = new EventSource("https://stream.radiomv.com/api/metadata/english/events");
es.onmessage = (e) => {
const now = JSON.parse(e.data);
document.getElementById("title").textContent = now.title;
};
GET /api/metadata/{station} no more than once every 10–15 seconds. All endpoints are rate-limited per IP; well-behaved clients will never notice the limits.
Testing From the Command Line
# Now playing
curl -s https://stream.radiomv.com/api/metadata/english
# Live metadata feed (Ctrl-C to stop)
curl -N https://stream.radiomv.com/api/metadata/english/events
# HLS master playlist
curl -s https://stream.radiomv.com/stream/english.m3u8
# Play in VLC / ffplay / mpv
vlc https://stream.radiomv.com/stream/english.m3u8
ffplay -nodisp https://stream.radiomv.com/stream/english.m3u8
# MP3: resolve the playlist, then probe the stream it points to
curl -s http://stream.radiomv.com/stream/english.m3u
Identify Your App (User-Agent)
Please send a User-Agent that names your app or service — not your HTTP library's default. It's how we recognize your integration in our listener analytics, notice when one of your releases changes behavior, and reach you before making a change that would affect you.
The shape we'd like (standard HTTP User-Agent format):
User-Agent: YourApp/2.1 (Android 14; https://yourapp.example)
- Product token first (
YourApp/version). Keep the name stable across releases — bump only the version. A stable token is what lets us count your listeners as yours. - In the parentheses: platform, plus a URL or email where we can reach you.
- Don't ship the library default (
okhttp/4.12.0,Dalvik/…,curl/8.x,Lavf/…). Generic-library agents are indistinguishable from scraper and bot traffic, which is exactly the traffic that gets scrutinized first during an abuse investigation.
Nothing is gated on the format — a missing or generic User-Agent still plays. But an identifiable one gets you better support and a heads-up before changes.
Being a Good Citizen
- One stream connection per active listener. Don't hold streams open for users who aren't listening.
- Reconnect with backoff. On stream error, retry after ~2s, then back off (4s, 8s, … capped around 30s). Hammering reconnects during a network blip makes recovery slower for everyone.
- Re-resolve on reconnect (MP3): fetch the
.m3uagain rather than reusing the last stream URL. For HLS this is automatic — just reload the master playlist URL. - Use SSE, not tight polling, for metadata.
- Identify your app in the
User-Agentheader (see above). - Don't proxy or re-host the streams. Link your users to the URLs above directly; that keeps geo-routing and quality adaptation working for them.
Stability of This Contract
The URLs and JSON shapes documented here are the supported public interface. Anything you discover beyond this page (internal hostnames, undocumented paths, extra fields) may change without notice. If this page and observed behavior disagree, tell us — we'll fix whichever is wrong.