Published on July 2, 2026

Music library sync is the process of reading, normalizing, and writing user music data (playlists, favorite tracks, and profile information) across multiple streaming services through a single integration. Instead of building separate connectors for each platform's proprietary API, you query one endpoint per data type and get a consistent response shape back, regardless of the source service.
Each streaming service exposes user library data differently. Some call them "saved tracks," others "liked songs." Playlist structures vary. Profile fields are inconsistent. Here is what you are working with:
| Data Type | What It Includes | MusicAPI Endpoint | Notes |
|---|---|---|---|
| Playlists | Name, description, track list, cover art, collaborative status | /get-user-playlists | Some services limit playlist count per request |
| Playlist Tracks | Ordered track list with metadata (title, artist, album, duration) | /get-playlist-tracks | Paginated for large playlists |
| Favorite Tracks | User's liked/saved/hearted tracks | /get-favorite-tracks | Field name varies by service; MusicAPI normalizes this |
| User Profile | Display name, email, subscription tier, country | /get-user-profile | Useful for entitlement checks |
| Playlist Info | Metadata for a single playlist (owner, follower count, public/private) | /get-playlist-info | Read-only on some services |
MusicAPI normalizes all of these into a consistent JSON schema. A favorite track from Tidal looks the same as one from Spotify in the response body. That normalization is what makes sync possible without writing per-service transformation logic.
A production sync pipeline has three stages: read, compare, and write. Here is how each one works.
Start by pulling the current library state from every connected service. With MusicAPI, this means one authenticated request per data type per service.
// Fetch favorite tracks from two services for the same user
const tidalFavorites = await fetch('https://api.musicapi.com/get-favorite-tracks/tidal', {
headers: { 'Authorization': `Bearer ${userToken}` }
});
const spotifyFavorites = await fetch('https://api.musicapi.com/get-favorite-tracks/spotify', {
headers: { 'Authorization': `Bearer ${userToken}` }
});
const tidalTracks = await tidalFavorites.json();
const spotifyTracks = await spotifyFavorites.json();
Both responses return the same shape: an array of track objects with name, artist, album, duration, and isrc fields. The isrc (International Standard Recording Code) is your best friend for cross-service matching. It is a universal track identifier that works across every major platform.
Sync gets interesting when the same user has different library states on different services. You need a conflict resolution strategy before you write a single line of sync code.
Three common approaches:
1. Source-of-truth model. One service is the canonical library. All others mirror it. Simple to implement, but users lose any additions they made on secondary services.
2. Union merge. Combine everything. If a track exists on any service, it should exist on all services. No data loss, but libraries grow monotonically (they never shrink).
3. Timestamp-based merge. Track when each item was added and use the most recent action as the truth. This requires storing metadata on your side, but it is the closest to what users expect.
For most applications, union merge is the safest default. It prevents data loss and the implementation is straightforward: diff the two sets by ISRC, and anything missing from one side gets added.
MusicAPI handles the hardest part of this process: normalizing data across 10+ streaming services into identical response shapes. You write the comparison logic once, and it works for every service pair. No per-platform transformation code, no maintaining separate SDKs, no chasing breaking API changes.
Once you know what is missing from each side, write the changes. For playlists, use the create-playlist endpoint. For individual tracks, add them to existing playlists or favorites.
// Create a playlist on Spotify that mirrors a Tidal playlist
const createResponse = await fetch('https://api.musicapi.com/create-playlist/spotify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${userToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Synced from Tidal - Workout Mix',
description: 'Auto-synced playlist',
tracks: missingTrackIds // ISRCs or service-specific IDs
})
});
You can see the full endpoint documentation for each service at /create-playlist/spotify, /create-playlist/tidal, and other supported services.
Here is a complete sync function that performs a union merge of favorite tracks between two services:
async function syncFavorites(userToken, serviceA = 'tidal', serviceB = 'spotify') {
const BASE = 'https://api.musicapi.com';
const headers = { 'Authorization': `Bearer ${userToken}` };
// 1. Fetch favorites from both services
const [favA, favB] = await Promise.all([
fetch(`${BASE}/get-favorite-tracks/${serviceA}`, { headers }).then(r => r.json()),
fetch(`${BASE}/get-favorite-tracks/${serviceB}`, { headers }).then(r => r.json())
]);
// 2. Build ISRC sets for comparison
const isrcsA = new Set(favA.tracks.map(t => t.isrc));
const isrcsB = new Set(favB.tracks.map(t => t.isrc));
// 3. Find tracks missing from each side
const missingFromA = favB.tracks.filter(t => !isrcsA.has(t.isrc));
const missingFromB = favA.tracks.filter(t => !isrcsB.has(t.isrc));
console.log(`Tracks to add to ${serviceA}: ${missingFromA.length}`);
console.log(`Tracks to add to ${serviceB}: ${missingFromB.length}`);
// 4. Sync missing tracks to each service
// (Implementation depends on your write endpoints)
return {
addedToA: missingFromA.length,
addedToB: missingFromB.length,
totalSynced: missingFromA.length + missingFromB.length
};
}
// Usage
const result = await syncFavorites(userToken, 'tidal', 'spotify');
// => { addedToA: 12, addedToB: 8, totalSynced: 20 }
This same pattern works for any service pair. Swap 'tidal' and 'spotify' for 'apple', 'deezer', 'youtube', or any other supported service. The response shape stays identical.
A user with 5,000 saved tracks and 200 playlists will break a naive sync implementation. Here is how to handle scale.
Pagination. MusicAPI endpoints return paginated responses for large collections. Always loop through pages until you have the complete dataset before running comparisons.
async function getAllFavorites(userToken, service) {
const headers = { 'Authorization': `Bearer ${userToken}` };
let allTracks = [];
let offset = 0;
const limit = 50;
while (true) {
const res = await fetch(
`https://api.musicapi.com/get-favorite-tracks/${service}?offset=${offset}&limit=${limit}`,
{ headers }
);
const data = await res.json();
allTracks = allTracks.concat(data.tracks);
if (data.tracks.length < limit) break;
offset += limit;
}
return allTracks;
}
Rate limits. Each streaming service enforces its own rate limits. MusicAPI's rate limiting layer handles per-service throttling for you, but you should still implement exponential backoff on your side for large batch operations. Check the Retry-After header when you receive a 429 response.
Incremental sync. Full library comparisons are expensive. After the initial sync, store a local snapshot of each user's library state (ISRCs + timestamps) and only fetch/compare changes since the last sync. This drops your API call volume by 90%+ for active users.
Use MusicAPI's unified authentication flow. You initialize auth once per service, handle the callback, and MusicAPI manages OAuth tokens and refresh cycles for every connected platform. No need to register separate developer apps with each service.
Some tracks exist on one service but not another due to licensing. When a track is unavailable on the target platform, your sync logic should log it as a skipped item and continue. You can use the ISRC to search for alternative versions or notify the user about unavailable tracks.
MusicAPI supports 10+ streaming services including Spotify, Tidal, Apple Music, YouTube Music, Deezer, and more. All services use the same endpoint structure and response format, so adding a new service to your sync pipeline is a one-line change.
MusicAPI returns an authentication error for that service. Your sync logic should catch this, skip the disconnected service, and prompt the user to reconnect through the auth flow. The user's data on other connected services remains unaffected.
MusicAPI works as a request-response API, so sync is batch-based. Most applications run sync on a schedule (every 15 minutes, hourly, or on user request). For near-real-time behavior, poll at shorter intervals or trigger sync when the user opens your app.
Break large sync operations into chunks. Fetch favorites and playlists separately, paginate through results, and process writes in batches of 50 or fewer. Use the incremental sync pattern described above to minimize data transfer after the initial full sync.
Ready to skip months of OAuth and SDK work? Start your free MusicAPI trial and connect 10+ streaming services with one unified API.