API Guidelines

Best practices, caching recommendations, and what to expect when integrating with the RadioMV API.

Overview

The RadioMV API consists of static JSON files served from the RadioMV CDN (stream.radiomv.com). This means:

Do's

Always fetch URLs from app config Never hardcode stream, metadata, or schedule URLs. Fetch appv3.json first and resolve each station's relative paths against config.baseUrl. This ensures your app automatically gets the correct URLs when we release new versions.

Recommended Flow

// 1. Fetch app config (hardcode only this URL)
const config = await fetch('https://stream.radiomv.com/static/appv3.json');
const data = await config.json();

// 2. Resolve the station's schedule path against baseUrl
const station = data.stations.find(s => s.id === "english");
if (station.schedule) {
    // 3. Fetch the schedule (not every station has one)
    const schedule = await fetch(data.config.baseUrl + station.schedule);
    const programs = (await schedule.json()).schedule;
}
Cache responses appropriately Schedule files change ~3 times per year. App configuration changes more frequently but not constantly. Cache aggressively.

Caching Recommendations

File Update Frequency Recommended Cache
appv3.json Weekly to monthly 24 hours, check version on app launch
Schedule files ~3 times per year 7 days, check lastUpdated periodically

Implementation Best Practices

Version Checking Example

// Smart fetching with version check
async function fetchWithVersionCheck(url, cachedData) {
    try {
        const response = await fetch(url);
        const data = await response.json();

        // For appv3.json
        if (data.config?.version === cachedData?.config?.version) {
            return cachedData; // No changes
        }

        // For schedule files
        if (data.lastUpdated === cachedData?.lastUpdated) {
            return cachedData; // No changes
        }

        return data; // New data
    } catch (error) {
        return cachedData; // Fallback to cache
    }
}

Don'ts

Avoid these common mistakes Following these guidelines ensures your integration remains stable and performant.

Things to Avoid

What to Expect

Update Frequency

Change Type Frequency Examples
Artwork updates Seasonally (~4x/year) Holiday themes, seasonal artwork
Schedule changes Rarely (~3x/year) New programs, time slot changes
Stream URL changes Very rare Infrastructure updates
New stations Very rare New language or channel launch
Schema changes Very rare New fields, structure changes

Breaking Changes Policy

We follow semantic versioning for schedule files:

Backwards Compatibility We strive to maintain backwards compatibility. New fields will be added as optional. Existing fields will not be removed without a major version bump.

Availability

Error Handling

Recommended Pattern

async function loadStationData() {
    const CACHE_KEY = 'radiomv_app_config';

    try {
        // Try to fetch fresh data
        const response = await fetch(
            'https://stream.radiomv.com/static/appv3.json',
            { timeout: 10000 }
        );

        if (!response.ok) {
            throw new Error(`HTTP ${response.status}`);
        }

        const data = await response.json();

        // Validate essential fields exist
        if (!data.stations || !Array.isArray(data.stations)) {
            throw new Error('Invalid response structure');
        }

        // Cache the valid response
        localStorage.setItem(CACHE_KEY, JSON.stringify(data));

        return data;

    } catch (error) {
        console.warn('Failed to fetch, using cache:', error);

        // Fall back to cached data
        const cached = localStorage.getItem(CACHE_KEY);
        if (cached) {
            return JSON.parse(cached);
        }

        // Fall back to bundled data
        return require('./fallback-config.json');
    }
}

Timezone Handling

All schedule times are in America/Los_Angeles (Pacific Time). To display in the user's local timezone:

function convertToLocalTime(timeStr, stationTimezone) {
    // timeStr is "HH:MM" format
    const [hours, minutes] = timeStr.split(':').map(Number);

    // Create date in station timezone
    const today = new Date();
    const dateStr = today.toISOString().split('T')[0];

    const stationDate = new Date(
        `${dateStr}T${timeStr}:00`
    );

    // Format in user's local timezone
    return stationDate.toLocaleTimeString('en-US', {
        hour: 'numeric',
        minute: '2-digit',
        timeZone: stationTimezone,
        timeZoneName: 'short'
    });
}

Support

For API issues or questions: