SoundCloud for Developers

Discover, connect and build

API Guide

The SoundCloud API provides endpoints for authentication, track upload and playback, social features, and search. This guide covers common integration patterns with code examples. For detailed endpoint specifications, see the API Explorer.

Key Facts

  • Base URL: https://api.soundcloud.com
  • Auth URL: https://secure.soundcloud.com
  • Auth method: OAuth 2.1 with PKCE
  • Token expiry: ~1 hour
  • Token refresh: single-use refresh tokens
  • Required header: Authorization: OAuth ACCESS_TOKEN
  • Supported audio formats: AIFF, WAVE, FLAC, OGG, MP2, MP3, AAC, AMR, WMA

Prerequisites

All API usage requires a registered application:

  1. Register your app
  2. Obtain your client_id and client_secret
  3. Authenticate (required for endpoints that access user resources)

Authentication

SoundCloud uses OAuth 2.1 for authentication. PKCE is required for the authorization code exchange.

If migrating from OAuth 2.0, see the differences in the RFC.

Supported Authorization Flows

Flow User Resources Access Server-side Implementation
Authorization Code Yes Yes
Client Credentials No Yes
  • Authorization Code: For applications that perform actions on a user's behalf (upload, access private content). Requires user consent.
  • Client Credentials: For applications accessing public resources only (search, playback, URL resolution). No user session required.

Sign in with SoundCloud

The Connect with SoundCloud button enables one-click OAuth registration and sign-in. After authorization, the application gains access to the user's account for uploading, playlist creation, and other user-scoped actions.

Authorization Code Flow

1. Redirect User to Authorization URL

Construct the authorization URL with the required parameters and redirect the user's browser to it. This step runs on the front-end.

# open in the browser

https://secure.soundcloud.com/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URI&response_type=code&code_challenge=CODE_CHALLENGE&code_challenge_method=S256&state=STATE

Parameters: - YOUR_CLIENT_ID: The client ID from application registration. - YOUR_REDIRECT_URI: The URI from application registration. The user is redirected here after authentication. - CODE_CHALLENGE: A PKCE code challenge. See What is PKCE? and PKCE generator sandbox. - STATE: A random string for CSRF protection. Verify this nonce after retrieving the token.

2. User Authorization

The user is redirected to SoundCloud to log in and approve the authorization request.

3. Obtain Access Token

After approval, SoundCloud redirects to your redirect_uri with a code query parameter. Exchange this code for an access token:

curl -X POST "https://secure.soundcloud.com/oauth/token" \
     -H  "accept: application/json; charset=utf-8" \
     -H  "Content-Type: application/x-www-form-urlencoded" \
     --data-urlencode "grant_type=authorization_code" \
     --data-urlencode "client_id=YOUR_CLIENT_ID" \
     --data-urlencode "client_secret=YOUR_CLIENT_SECRET" \
     --data-urlencode "redirect_uri=YOUR_REDIRECT_URI" \
     --data-urlencode "code_verifier=YOUR_PKCE_GENERATED_CODE_VERIFIER" \
     --data-urlencode "code=YOUR_CODE"

Parameters: - YOUR_CLIENT_ID, YOUR_CLIENT_SECRET: From application registration. - YOUR_PKCE_GENERATED_CODE_VERIFIER: Generated by your application during step 1. - YOUR_REDIRECT_URI: Must match the URI used in the authorization request exactly. - YOUR_CODE: The authorization code received from the authorization server.

4. Store and Use Tokens

The response contains access_token, refresh_token, expires_in, and scope. Store these values associated with the user. Use the access_token for subsequent API requests and the refresh_token to renew expired tokens.

curl "https://api.soundcloud.com/me" \
       -H "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Client Credentials Token Exchange Flow

The Client Credentials flow authenticates an application (not a user) to access public resources. Send client_id and client_secret via HTTP Basic authentication to obtain an access token.

curl -X POST "https://secure.soundcloud.com/oauth/token" \
     -H  "accept: application/json; charset=utf-8" \
     -H  "Content-Type: application/x-www-form-urlencoded" \
     -H  "Authorization: Basic Base64(client_id:client_secret)" \
     --data-urlencode "grant_type=client_credentials"

# If your client_id is "my_client_id" and client_secret is "my_client_secret"
# The concatenated string would be "my_client_id:my_client_secret"
# The Base64 encoded string of "my_client_id:my_client_secret" is "bXlfY2xpZW50X2lkOm15X2NsaWVudF9zZWNyZXQ="

For the client_credentials grant type, only HTTP Basic authentication (Authorization: Basic ...) is supported. Sending credentials in the request body is not supported.

The response contains access_token, refresh_token, expires_in, and scope. Store and reuse the token; use refresh_token to renew expired tokens.

Constraints — Client Credentials token rate limits: - 50 tokens per 12 hours per application - 30 tokens per 1 hour per IP address - Reuse tokens across service instances - Implement the refresh token flow to stay within limits

Note: All clients are currently treated as confidential rather than public, meaning a secret is required to obtain a token.

Refreshing Tokens

Access tokens expire after approximately 1 hour. Use the refresh_token to obtain a new access token. Each refresh token is single-use.

Note: All clients are currently treated as confidential rather than public, meaning a secret is required to obtain a token.

curl -X POST "https://secure.soundcloud.com/oauth/token" \
     -H  "accept: application/json; charset=utf-8" \
     -H  "Content-Type: application/x-www-form-urlencoded" \
     --data-urlencode "grant_type=refresh_token" \
     --data-urlencode "client_id=YOUR_CLIENT_ID" \
     --data-urlencode "client_secret=YOUR_CLIENT_SECRET" \
     --data-urlencode "refresh_token=YOUR_TOKEN"

Mobile and Desktop Applications

Mobile and desktop applications use the same authorization code flow as web applications. Use a custom protocol scheme for the redirect_uri (e.g., my-app://soundcloud/callback).

For mobile devices, add display=popup to the authorization URL query string to use the mobile-optimized connect screen.

Signing Out

To sign out the user, send the access_token as follows:

curl -X POST "https://secure.soundcloud.com/sign-out" \
     -H "Content-Type: application/json" \
     -d '{"access_token": "ACCESS_TOKEN"}'

Error responses have the following format: ```

Error:

{ "error": "XXXX" } ```

Sign-out error details:

Response Status Description
bad_request 400 body is missing access token
unauthorized 401 this token is associated with a session that is already invalid

Accessing Resources

Every API request requires an Authorization header:

-H "Authorization: OAuth ACCESS_TOKEN"

Requests without this header return 401 Unauthorized. See the Authentication section for supported auth methods.

Getting Information about the Authenticated User

The /me endpoint returns profile information for the authenticated user.

curl "https://api.soundcloud.com/me" \
       -H "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Uploading Tracks

The API supports uploading, managing, and sharing tracks. Supported audio formats: AIFF, WAVE, FLAC, OGG, MP2, MP3, AAC, AMR, WMA.

Uploading Audio Files

Send a POST request with multipart/form-data to the /tracks endpoint.

Maximum request body size: 500MB.

curl -X POST "https://api.soundcloud.com/tracks" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN" \
       -H  "Content-Type: multipart/form-data" \
       -F "track[title]=YOUR_TITLE" \
       -F "track[asset_data]=@PATH_TO_A_FILE"

On success, the track is queued for encoding.

Updating Metadata

To update track metadata, send a PUT request to the /tracks/:id endpoint with the properties to update.

Track artwork can be updated via the artwork_data parameter. The audio file cannot be updated after upload.

# Multipart request
curl -X PUT "https://api.soundcloud.com/tracks/TRACK_ID" \
       -H  "accept: application/json; charset=utf-8" \
       -H  "Content-Type: multipart/form-data" \
       -H "Authorization: OAuth ACCESS_TOKEN" \
       -F "track[title]=YOUR_TITLE" \
       -F "track[description]=YOUR_DESCRIPTION"  \
       -F "track[artwork_data]=@PATH_TO_FILE"

# JSON request
curl -X PUT "https://api.soundcloud.com/tracks/TRACK_ID"  \
      -H  "accept: application/json; charset=utf-8" \
      -H  "Content-Type: application/json"  \
      -H  "Authorization: OAuth ACCESS_TOKEN"  \
      -d '{"track":{"title":"NEW TITLE"}}'

Creating Playlists

Playlists group tracks for sharing. A track can belong to multiple playlists. Playlists can be public or private.

Create a playlist by sending a POST request to /playlists with playlist metadata and a list of track IDs.

curl -X POST "https://api.soundcloud.com/playlists" \
       -H  "accept: application/json; charset=utf-8" \
       -H  "Content-Type: application/json" \
       -H "Authorization: OAuth ACCESS_TOKEN" \
       -d '{"playlist": {"title":"YOUR_TITLE", "description":"YOUR_DESCRIPTION", "sharing":"public", "tracks":[{"id":1},{"id":2},{"id":3}]}}'

Adding Tracks to a Playlist

Add tracks to an existing playlist by updating the tracks property via PUT.

curl -X PUT "https://api.soundcloud.com/playlists/PLAYLIST_ID" \
       -H  "accept: application/json; charset=utf-8" \
       -H  "Content-Type: application/json" \
       -H "Authorization: OAuth ACCESS_TOKEN" \
       -d '{"playlist": {"tracks":[{"id":1}, {"id":2}, {"id":3}]}}'

Accessing Playlists

Retrieve tracks in a playlist with a GET request to /playlists/:id.

curl -X GET "https://api.soundcloud.com/playlists/PLAYLIST_ID?show_tracks=false" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Playing Tracks

Tracks and playlists can be played from your application by embedding the SoundCloud widget or using stream URLs with a custom audio player. The Widget API provides programmatic control and event handling.

Embedding a SoundCloud Widget

Use the oEmbed endpoint to retrieve embed code for any track or playlist URL.

See also: Embedded player guide, Widget API.

Streaming Tracks

Custom player streaming requires proper attribution per the Terms of Use and Attribution Guidelines:

  1. Credit the uploader as the creator of the track
  2. Credit SoundCloud as the source by including one of the logos
  3. Link to the SoundCloud URL containing the work
  4. If the track is private, link to the profile of the creator

To stream with a custom player, retrieve the track resource and use its stream_url property. A GET request to the stream URL returns available transcodings.

Public tracks can be streamed without a user session. Private tracks require an authorized user session and a secret_token.

# request a track you want to stream
curl -X GET "https://api.soundcloud.com/tracks/TRACK_ID" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

# extract stream_url when available from a response
curl -X GET "https://api.soundcloud.com/tracks/TRACK_ID/stream" \
         -H  "accept: application/json; charset=utf-8" \
         -H "Authorization: OAuth ACCESS_TOKEN"

See also: /oembed, HTML5 Widget API.

Restricted Access

Not all tracks are available for off-platform streaming. Tracks may be restricted by the creator, paywalled, or geo-blocked. Restricted tracks have no stream_url and their access field is set to blocked. Calling /tracks/:id/streams for a blocked track returns an error.

Track access levels: - playable — the track is fully streamable - preview — a preview snippet is available - blocked — not streamable, only metadata is provided

The access filter parameter can be used when searching or fetching tracks to include only tracks with specific access levels. See the API Explorer for details.

Comments

Send a POST request to /tracks/:track_id/comments to create a comment. Include a timestamp parameter (in milliseconds from track start) for a timed comment. Omitting it creates a non-timed comment.

Comments cannot be posted on tracks where the creator has disabled comments.

curl -X POST "https://api.soundcloud.com/tracks/YOUR_TRACK_ID/comments"  \
       -H  "accept: application/json; charset=utf-8" \
       -H  "Content-Type: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN" \
       -d '{"comment":{"body":"YOUR_COMMENT","timestamp":12345}}'

Retrieve comments for a track:

curl -X GET "https://api.soundcloud.com/tracks/YOUR_TRACK_ID/comments?limit=3&linked_partitioning=true" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Follow & Like

The API supports following users and liking tracks or playlists. Followed users' tracks and reposts appear in the activity feed.

Follow a user via PUT /me/followings/:user_id:

curl -X PUT "https://api.soundcloud.com/me/followings/USER_ID" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Like a track or playlist via the /likes/ endpoints:

# liking a track
curl -X POST "https://api.soundcloud.com/likes/tracks/TRACK_ID" \
       -H "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

# liking a playlist
curl -X POST "https://api.soundcloud.com/likes/playlists/PLAYLIST_ID" \
       -H "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Search

Search tracks, users, and playlists using the q parameter, which matches against fields like title, username, and description.

# search for playable tracks
curl -X GET "https://api.soundcloud.com/tracks?q=hello&ids=1,2,3&genres=Pop,House&access=playable&limit=3&linked_partitioning=true" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Range filters are supported for bpm, duration, and other fields:

curl -X GET "https://api.soundcloud.com/tracks?q=hello&ids=1,2,3&genres=Pop,House&bpm%5Bfrom%5D=120&duration%5Bfrom%5D=30000&access=playable&limit=3&linked_partitioning=true" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

See the API Explorer for all available search fields and filters.

Pagination

Collection responses return up to 50 items by default (maximum 200). Pass linked_partitioning=true to enable pagination. Paginated responses include a next_href property pointing to the next page. When next_href is absent, there are no more results.

# fetch first 25 user's playlists
curl -X GET "https://api.soundcloud.com/me/playlists?show_tracks=false&linked_partitioning=true&limit=25" \
       -H  "accept: application/json; charset=utf-8" \
       -H "Authorization: OAuth ACCESS_TOKEN"

# response contains 'next_href': "https://api.soundcloud.com/playlists?show_tracks=false&page_size=25&cursor=1234567"

SoundCloud URLs

The /resolve endpoint converts a SoundCloud permalink URL into a full API resource representation.

curl -X GET "https://api.soundcloud.com/resolve?url=https://soundcloud.com/PERMALINK" \
       -H  "accept: */*" \
       -H "Authorization: OAuth ACCESS_TOKEN"

Cross Domain Requests

The API supports CORS for browser-based JavaScript requests. JSONP is also supported via a callback query parameter.

const response = await fetch("https://api.soundcloud.com/tracks?ids=1,2,3", {
  headers: {
    "Accept": "application/json; charset=utf-8",
    "Authorization": "OAuth ACCESS_TOKEN"
  }
});
const tracks = await response.json();
tracks.forEach(track => console.log(track.title));

Errors

The API returns standard HTTP status codes with JSON error descriptions.

# try fetching a non-existing user
curl -X GET "https://api.soundcloud.com/users/INVALID_ID" \
       -H  "accept: application/json; charset=utf-8" \
       -H  "Authorization: OAuth ACCESS_TOKEN"

# response 404 Error: Not Found
{
  "code": 404,
  "message": "404 - Not Found",
  "link": "https://developers.soundcloud.com/docs/api/explorer/open-api",
  "status": "404 - Not Found",
  "errors": [
    {
      "error_message": "404 - Not Found"
    }
  ],
  "error": null
}

HTTP Status Codes

400 Bad Request

The request was malformed or missing required parameters. Consult the API Explorer for endpoint requirements.

401 Unauthorized

Authentication failed. Verify the Authorization header is present and contains a valid token.

Public endpoints accept tokens from the Client Credentials flow. User-specific actions require an Authorization Code token. See the Authentication section.

OAuth tokens expire and must be refreshed to avoid 401 errors.

403 Forbidden

The authenticated user does not have permission to access this resource.

404 Not Found

The requested resource does not exist. Verify the URL path and resource ID.

406 Not Accessible

The server cannot produce a response matching the request's Accept header.

422 Unprocessable Entity

One or more parameters failed validation (e.g., wrong data type such as an array where a string was expected).

429 Too Many Requests

The request exceeded a rate limit. See the Rate Limits page for details.

500 Internal Server Error

An unexpected server error occurred.

503 Service Unavailable

The service is temporarily unavailable. Implement retry logic with backoff.

504 Gateway Timeout

The server did not receive a timely upstream response. The request may still have been processed; verify resource state before retrying.