Published on July 3, 2026

SoundCloud occupies a unique position in the streaming landscape. While Spotify and Apple Music dominate subscriber counts, SoundCloud is where independent artists, podcasters, and bedroom producers publish first. For developers, that means access to a deep catalog of content that does not exist anywhere else, and an API that reflects SoundCloud's creator-first identity.
This guide covers what you need to know to build SoundCloud integrations in 2026: how authentication works, which endpoints matter, and how to include SoundCloud in a multi-service app without writing a separate integration for every platform.
SoundCloud gives developers access to one of the largest independent music catalogs on the internet, with a user base of creators and listeners that overlaps minimally with mainstream streaming services. The platform hosts over 300 million tracks, the majority of which are not available elsewhere. For applications targeting indie music discovery, podcast listening, or creator-focused tools, SoundCloud integration is a meaningful differentiator.
SoundCloud's API access in 2026 follows an application-based model. Developer access requires registering an application on the SoundCloud developer portal, which grants OAuth credentials for user-authenticated flows. Public catalog access (searching tracks, browsing public profiles) does not require user authentication, but anything involving user data, playlists, or listening history does.
The developer use cases that drive most SoundCloud integrations:
SoundCloud uses OAuth 2.0 with authorization code flow for user-authenticated requests. The flow is standard: your app redirects the user to SoundCloud's auth page, the user grants permission, SoundCloud redirects back with an authorization code, and your server exchanges that code for access and refresh tokens.
Here is how that looks using MusicAPI's unified authentication system, which normalizes the OAuth flow across all connected services:
const response = await fetch('https://api.musicapi.com/auth/init', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
service: 'soundcloud',
callbackUrl: 'https://yourapp.com/auth/callback',
scopes: ['non-expiring']
})
});
const { authUrl } = await response.json();
// Redirect the user to authUrl
See the initializing authentication docs for the full scope reference.
app.get('/auth/callback', async (req, res) => {
const { code, state } = req.query;
const tokenResponse = await fetch('https://api.musicapi.com/auth/callback', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ code, state })
});
const { userId, service, accessToken } = await tokenResponse.json();
res.redirect('/dashboard');
});
SoundCloud tokens have historically behaved differently depending on the scope granted at authorization. With the non-expiring scope, access tokens issued to registered applications persist longer than standard OAuth tokens. This is convenient but worth managing carefully: rotating tokens on a schedule is better practice than relying on indefinite validity.
When building with MusicAPI, token refresh is handled automatically across all services. Your application code calls the API endpoint, and the library manages whether the underlying SoundCloud token needs refreshing before the request proceeds. You write one integration path; the service-level token lifecycle is handled for you.
SoundCloud's API exposes endpoints across several functional categories. Here is where the coverage stands for the common developer use cases and how MusicAPI normalizes them:
| Use Case | SoundCloud Endpoint | MusicAPI Normalized Endpoint | Notes |
|---|---|---|---|
| Get user profile | GET /me | GET /user/profile | Includes follower count, track count, plan |
| Get user playlists | GET /me/playlists | GET /user/playlists | Returns playlist metadata |
| Get playlist tracks | GET /playlists/{id}/tracks | GET /playlists/{id}/tracks | See SoundCloud playlist tracks |
| Get favorite tracks | GET /me/likes/tracks | GET /user/favorites | Paginated, up to 200 per page |
| Search tracks | GET /tracks?q={query} | GET /search/tracks | Public, no auth required |
| Get user's track history | GET /me/play-history/tracks | GET /user/history | Requires explicit permission |
const profile = await fetch('https://api.musicapi.com/user/profile', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'X-User-Token': userAccessToken
}
});
const { user } = await profile.json();
// user.username, user.followerCount, user.trackCount, user.plan
The most common SoundCloud developer use case is reading a user's playlists and the tracks inside them. The SoundCloud playlist tracks endpoint returns a paginated list of track objects with metadata including title, artist, duration, artwork URL, and stream URL (for apps with appropriate access).
const playlists = await fetch('https://api.musicapi.com/user/playlists', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'X-User-Token': userAccessToken
}
});
const { items } = await playlists.json();
// Fetch tracks for the first playlist
const tracks = await fetch(
`https://api.musicapi.com/playlists/${items[0].id}/tracks`,
{
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'X-User-Token': userAccessToken
}
}
);
const { tracks: trackList } = await tracks.json();
// Each track: id, title, artist, duration, artworkUrl, streamUrl
const favorites = await fetch('https://api.musicapi.com/user/favorites', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'X-User-Token': userAccessToken
}
});
const { items } = await favorites.json();
// Normalized track objects, consistent format across all services
SoundCloud's API has some quirks that surface when you try to include it alongside services like Spotify or Apple Music.
The challenge: SoundCloud's track objects include fields that do not map cleanly to mainstream streaming catalogs — genre tags as free-text strings rather than standardized categories, user-generated artwork rather than label-approved assets, stream counts as the primary popularity signal rather than chart position. When your app aggregates content from multiple services, you need to handle these differences without special-casing SoundCloud throughout your codebase.
This is where normalized response shapes pay dividends. When MusicAPI returns a track from SoundCloud, the response uses the same fields as a track from any other supported service. Your frontend renders SoundCloud tracks the same way it renders any other track, and your data layer processes them identically.
Here is what fetching playlist tracks via MusicAPI looks like when the underlying service is SoundCloud:
async function getPlaylistTracks(playlistId, userToken) {
const response = await fetch(
`https://api.musicapi.com/playlists/${playlistId}/tracks`,
{
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'X-User-Token': userToken
}
}
);
const { tracks } = await response.json();
// Normalized response — same shape regardless of service
return tracks.map(track => ({
id: track.id,
title: track.title,
artist: track.artist.name,
duration: track.durationMs,
artwork: track.artworkUrl,
service: track.service // "soundcloud"
}));
}
Compare this to what you would write working directly with SoundCloud's API: different field names (user.username instead of artist.name, duration in milliseconds without a guaranteed field name, artwork at artwork_url versus a structured image object). Multiply that by every service in your app, and the normalization layer saves significant maintenance over time.
MusicAPI normalizes SoundCloud's unique response shapes alongside 11 other services through a single integration. Instead of writing and maintaining per-service response parsers, you write one. See the supported features reference for the full capability matrix.
SoundCloud enforces rate limits per API credential, not per user session. The limits are not publicly documented in precise terms, but practical experience puts the safe threshold around 15,000 requests per day for registered applications in good standing. Burst limits apply separately — sustained bursts above roughly 10 requests per second will trigger throttling.
MusicAPI's rate limiting layer manages per-service throttling so you do not have to track these thresholds manually. Your application sets a usage budget; MusicAPI distributes requests across services within their safe windows and queues excess requests rather than dropping them.
SoundCloud uses cursor-based pagination on most collection endpoints. The response includes a next_href field when more results exist. Follow that URL directly rather than constructing offset-based parameters:
async function getAllFavorites(userToken) {
const allTracks = [];
let nextUrl = 'https://api.musicapi.com/user/favorites';
while (nextUrl) {
const response = await fetch(nextUrl, {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'X-User-Token': userToken
}
});
const { items, pagination } = await response.json();
allTracks.push(...items);
nextUrl = pagination.nextUrl || null;
}
return allTracks;
}
MusicAPI standardizes pagination across services — pagination.nextUrl works the same way whether the underlying service uses cursors (SoundCloud, Tidal) or page-based offsets (Spotify, Deezer). You write the pagination loop once.
SoundCloud returns standard HTTP status codes. The ones worth explicit handling:
| Status | Meaning | Recovery |
|---|---|---|
| 401 | Token expired or invalid | Refresh token and retry once |
| 403 | Insufficient scope | Surface a re-auth prompt to the user |
| 429 | Rate limit exceeded | Back off with exponential retry |
| 404 | Resource not found or private | Show empty state; do not retry |
async function fetchWithRetry(url, headers, maxRetries = 2) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
const response = await fetch(url, { headers });
if (response.ok) return response.json();
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 5;
await new Promise(r => setTimeout(r, retryAfter * 1000));
continue;
}
if (response.status === 401 && attempt === 0) {
await refreshToken();
continue;
}
throw new Error(`Request failed: ${response.status}`);
}
}
Yes. SoundCloud maintains an API program for registered developer applications. Public catalog access (search, public track metadata) is available without user authentication. User-specific data (playlists, favorites, listening history) requires OAuth authorization from the user. Access requires registering an application through SoundCloud's developer portal to obtain client credentials.
SoundCloud uses standard OAuth 2.0 authorization code flow. Your app redirects the user to SoundCloud's auth endpoint with your client ID and requested scopes. After the user approves, SoundCloud redirects back with an authorization code that your server exchanges for access and refresh tokens. See the MusicAPI auth documentation for implementation examples that work across SoundCloud and other services.
Yes. SoundCloud's API exposes playlist metadata and track listings for authenticated users. Public playlists can also be accessed without authentication given the playlist's numeric ID. The SoundCloud playlist tracks endpoint covers this in detail. Track objects include title, artist, duration, artwork, and (for apps with stream access) stream URLs.
SoundCloud does not publicly document exact rate limit thresholds. Practical limits for registered applications are around 15,000 requests per day with burst limits around 10 requests per second. Exceeding these returns HTTP 429 with a Retry-After header. Using a unified API layer with built-in rate limit management keeps you within safe thresholds automatically.
SoundCloud's API returns data in formats unique to the platform — field names, data structures, and pagination patterns differ from other streaming services. A unified API normalizes these differences, returning SoundCloud data in the same shape as data from any other service. You write one integration and one response parser rather than one per service. Token refresh, rate limit management, and pagination handling are abstracted at the API layer.
Yes, and this is one of the most common reasons developers use a unified music API. Each service has its own OAuth flow, its own endpoint structure, and its own response schema. MusicAPI connects to all supported services through a single integration point. Authenticate users with any combination of services, then read playlists, tracks, and user data through consistent endpoints regardless of which service is the source.
SoundCloud's independent catalog and creator community make it worth including in any music application that cares about breadth. The integration work is real, but it follows the same patterns as other streaming services once you know what to expect.
Ready to skip months of OAuth and SDK work? Start your free MusicAPI trial and connect 10+ streaming services with one unified API.