# MusicLink API: full documentation for AI assistants

This file is the complete MusicLink API documentation as plain markdown. Use it to write code against the API.

## Essentials

- Base URL: `https://api.musiclink.one`
- Authentication: header `Authorization: Bearer <API key>`. Read the key from the `MUSICLINK_API_KEY` environment variable. Call the API from a server, never from browser or mobile code.
- Main endpoint: `GET /v2/resolve?q=<link | ISRC | UPC | ID>` returns the item with a link for every platform in `data[].platforms`.
- Single answer: `GET /v2/convert?q=<input>&to=<platform key | isrc | upc>` returns one value in `data.to.value`. Faster.
- Every response is JSON: `{ "success": true, "data": … }` or `{ "success": false, "error": "…" }`. Check `success`.
- `data` from resolve is an array (an ISRC can match several releases). `data` from convert is an object.
- The first lookup of an item can take 10–15 seconds. Use an HTTP timeout of at least 30 seconds.
- On `429`, wait the seconds in the `Retry-After` header, then retry. Retry `500` after a short pause. Don't retry `400`, `401` or `404`.
- Example responses below are real, recorded from the API.

## Pages

- [API Reference](https://musiclink.one/docs): Send one link, ISRC or UPC. Get back the same song, album or artist on every streaming platform.
- [TypeScript SDK](https://musiclink.one/docs/sdk): A typed client for Node.js, so you call methods instead of building requests.

---

## API Reference

Send one link, ISRC or UPC. Get back the same song, album or artist on every streaming platform.

Source: https://musiclink.one/docs

### Authentication

All requests require an `Authorization: Bearer <key>` header. Get yours from the [dashboard](https://musiclink.one/dashboard/keys). Base URL: `https://api.musiclink.one`

```bash
curl "https://api.musiclink.one/v2/resolve?q=GBARL9300135" \
  -H "Authorization: Bearer <your-key>"
```

### Send a request

`GET /v2/resolve?q=<input>`

Resolve takes one thing you know about a song, album or artist and returns its link on every platform, with its details.

```bash
curl -G "https://api.musiclink.one/v2/resolve" \
  --data-urlencode "q=https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT" \
  -H "Authorization: Bearer $MUSICLINK_API_KEY"
```

Response (200 OK):

```json
{
  "success": true,
  "data": [
    {
      "type": "track",
      "id": "h8aN_1K9",
      "url": "https://musiclink.one/song/rick-astley/never-gonna-give-you-up?i=2",
      "embed_url": "https://musiclink.one/embed/s/h8aN_1K9",
      "title": "Never Gonna Give You Up",
      "artist": "Rick Astley",
      "image_url": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/ce/6d/5b/ce6d5b48-8c36-b990-3b9c-81862fadb459/0859381157694.jpg/600x600bb.jpg",
      "isrc": "GBARL0600786",
      "duration_ms": 213573,
      "preview_url": "https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview221/v4/62/ff/3a/62ff3abe-bc6d-a7d0-31b0-71cbec9aaa24/mzaf_13802296211720217737.plus.aac.p.m4a",
      "platforms": {
        "musiclink": "https://musiclink.one/song/rick-astley/never-gonna-give-you-up?i=2",
        "spotify": "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
        "apple_music": "https://music.apple.com/song/1559885421",
        "deezer": "https://www.deezer.com/track/14408104",
        "tidal": "https://listen.tidal.com/track/491206012",
        "youtube": "https://youtube.com/watch?v=dQw4w9WgXcQ",
        "soundcloud": "https://soundcloud.com/pajlada/rick-astley-never-gonna-give-you-up",
        "qobuz": "https://open.qobuz.com/track/385574059",
        "audius": "https://audius.co/tracks/4k3v4",
        "shazam": "https://www.shazam.com/song/1773293184/never-gonna-give-you-up",
        "yandex": "https://music.yandex.ru/track/609676",
        "anghami": "https://play.anghami.com/song/106295734?refer=linktree",
        "napster": "https://play.napster.com/track/tra.416878691",
        "pandora": "https://www.pandora.com/TR:8526",
        "bandcamp": "https://matthewrobertadamski2.bandcamp.com/track/never-gonna-give-you-up-2",
        "boomplay": "https://www.boomplay.com/songs/3569876",
        "jiosaavn": "https://www.jiosaavn.com/song/never-gonna-give-you-up/HzkgaC4dDgI",
        "audiomack": "https://audiomack.com/rick-astley/song/never-gonna-give-you-up-1",
        "amazon_music": "https://music.amazon.com/albums/B0DZTQLXGX?trackAsin=B0DZTSF3YS",
        "amazon_store": "https://amazon.com/dp/B0DZTSF3YS",
        "youtube_music": "https://music.youtube.com/watch?v=dQw4w9WgXcQ"
      }
    }
  ]
}
```

The first lookup of an item searches every platform and takes 10–15 seconds, so set a 30-second timeout. Later lookups of the same item come from cache.

- `q` (string, required): One of the [inputs](#inputs): a link, an ISRC, a UPC, a MusicLink ID, or a service's own ID. Up to 2,048 characters, URL-encoded.

- `type` (track | album | artist): Optional. Default: detected from `q`; a bare ID counts as a `track`. Set `album` or `artist` when `q` is the ID of an album or an artist. `song` is accepted as `track`.

- `platform` (one of the values below): Required when `q` is a bare ID, otherwise leave it out. Which values work depends on what the ID is for (`apple` works too, for `apple_music`):
  Songs: `musiclink`, `isrc`, `spotify`, `apple_music`, `youtube`, `youtube_music`, `soundcloud`, `deezer`, `tidal`
  Albums: `musiclink`, `upc`, `spotify`, `apple_music`, `youtube_music`, `deezer`, `tidal`, `soundcloud`
  Artists: `musiclink`, `spotify`, `apple_music`, `soundcloud`, `deezer`, `tidal`, `youtube_music`

- `include` (comma-separated list): Optional. Default: nothing extra. Any of: `related.artists` (every credited artist; songs and albums), `related.album` (the album a song is on; songs only), `platform_ids` (each service's own ID). See [Responses](#responses).

### Convert one link

`GET /v2/convert?q=<input>&to=<target>`

Convert answers one question, like "what's this song's ISRC?" or "what's its Apple Music link?", and searches only that one platform, so it's faster.

```bash
curl -G "https://api.musiclink.one/v2/convert" \
  --data-urlencode "q=https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT" \
  --data-urlencode "to=isrc" \
  -H "Authorization: Bearer $MUSICLINK_API_KEY"
```

Response (200 OK):

```json
{
  "success": true,
  "data": {
    "type": "track",
    "input": {
      "q": "https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT",
      "to": "isrc"
    },
    "from": {
      "platform": "spotify",
      "id": "4cOdK2wGLETKBW3PvgPWqT"
    },
    "to": {
      "platform": "isrc",
      "value": "GBARL0600786"
    },
    "item": {
      "title": "Never Gonna Give You Up",
      "artist": "Rick Astley",
      "image_url": "https://is1-ssl.mzstatic.com/image/thumb/Music124/v4/ce/6d/5b/ce6d5b48-8c36-b990-3b9c-81862fadb459/0859381157694.jpg/600x600bb.jpg",
      "isrc": "GBARL0600786",
      "duration_ms": 213573
    }
  }
}
```

- `to` (one of the values below, required): What you want back. The values depend on what `q` is:
  Songs: `spotify`, `apple_music`, `youtube`, `youtube_music`, `deezer`, `tidal`, `soundcloud`, `amazon_music`, `amazon_store`, `pandora`, `qobuz`, `yandex`, `boomplay`, `anghami`, `audiomack`, `shazam`, `jiosaavn`, `bandcamp`, `isrc`
  Albums: `spotify`, `apple_music`, `youtube_music`, `deezer`, `tidal`, `soundcloud`, `amazon_music`, `pandora`, `audiomack`, `anghami`, `boomplay`, `jiosaavn`, `bandcamp`, `qobuz`, `shazam`, `yandex`, `amazon_store`, `upc`
  Artists: `spotify`, `apple_music`, `deezer`, `tidal`, `soundcloud`, `youtube_music`, `youtube`, `amazon_music`, `pandora`, `audiomack`, `anghami`, `jiosaavn`, `qobuz`, `bandcamp`

- `q · type · platform`: The same as in [resolve](#send-a-request).

The response's `data` is a single object:

- `data.to.value` (string): The answer: a URL for a platform, the 12-character ISRC for `isrc`, the 12–14 digit UPC for `upc`.

- `data.from` (object): Where `q` was read from: `platform` (a key from [Platforms](#platforms)) and `id` (that service's ID).

- `data.item` (object or null): For display: `title`, `artist` and `image_url`, plus `isrc` and `duration_ms` for a song. For an artist, `title` is the name and `artist` is `null`. Can be `null`, for example when `q` itself already held the answer; don't depend on it.

`404`: the item isn't on the platform in `to`. `422`: convert can't handle this `q`; send the same request to resolve.

### Inputs

| Input | Format | Example | Also send |
| --- | --- | --- | --- |
| Link | A song, album or artist URL from a service in [Platforms](#platforms), a share link that redirects to one (`link.deezer.com`, `spotify.link`, `on.soundcloud.com`, `apple.co`), or a `spotify:track:…` URI | `https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT` | — (a link says what it is, so `type` and `platform` are ignored) |
| ISRC | 12 characters: 2 letters, 3 letters or digits, 7 digits. Dashes are fine | `GBARL9300135` | — |
| UPC | 12–14 digits; always an album | `0724384960650` | — |
| MusicLink ID | The `id` from an earlier response | `huUKtw-D` | `platform=musiclink`, and `type` for an album or artist |
| Service ID | The ID in that service's own link | `4cOdK2wGLETKBW3PvgPWqT` | `platform` (like `spotify`), and `type` for an album or artist |

One recording can be on several releases (a single, an album, a compilation), so an ISRC can return several items in `data`. Each item's `platforms` links to the same song; `data[0]` is enough for a link.

### Responses

Resolve answers with one of two shapes: a list of matches, or an error with an error status.

```typescript
type ResolveResponse =
  | { success: true; data: Item[] } // one item per match
  | { success: false; error: string };

type Item = Song | Album | Artist;
```

A field with no value is left out, never `null`, so the fields marked `?` may be missing. New fields may be added; ignore the ones you don't use.

#### Every item

```typescript
interface BaseItem {
  type: "track" | "album" | "artist";
  id?: string; // MusicLink ID. Send it back as `q` with `platform=musiclink` for the fastest lookup
  url?: string; // the item's MusicLink page
  embed_url?: string; // a player for an <iframe>
  image_url?: string; // artwork, or the artist's photo
  platforms: { [key: string]: string }; // platform key → URL, only where it was found
  platform_ids?: { [key: string]: string }; // platform key → that service's ID; only with include=platform_ids
}
```

Platform keys are listed in [Platforms](#platforms); a missing key means the item wasn't found there.

#### Songs

```typescript
interface Song extends BaseItem {
  type: "track";
  title?: string;
  artist?: string; // artist credit, as on the release
  isrc?: string; // 12-character recording code
  duration_ms?: number; // length in milliseconds
  preview_url?: string; // a 30-second audio clip
  related?: Related; // with include=related.artists or related.album
}
```

#### Albums

```typescript
interface Album extends BaseItem {
  type: "album";
  title?: string;
  artist?: string; // album artist
  upc?: string; // 12–14 digit barcode
  track_count?: number;
  release_date?: string; // YYYY-MM-DD
  related?: Related; // with include=related.artists
}
```

#### Artists

```typescript
interface Artist extends BaseItem {
  type: "artist";
  name?: string;
  genres?: string[]; // like ["Pop"]
  bio?: string; // short biography
  // Only the networks found: website, instagram, twitter, facebook, tiktok, youtube, soundcloud, wikidata
  social_links?: { [network: string]: string };
  // Only what's known: born, formed, hometown, country, genre, musicbrainz_id, isni
  artist_info?: { [key: string]: string };
}
```

#### Related artists and album

With `include=related.artists` or `include=related.album`, songs and albums get a `related` object with just the parts you asked for.

```typescript
interface Related {
  artists?: RelatedEntry[];
  album?: RelatedEntry;
}

interface RelatedEntry {
  name: string; // artist or album name
  id: string | null; // its MusicLink ID
  status: "resolved" | "stub"; // stub: only its name and a few IDs are known yet
  // resolved: its MusicLink page. stub: an API URL; request it with your key to get the full item
  url: string | null;
  query: string; // the same lookup as a path after /v2, like /resolve?q=mjfLhv4135mo&type=artist&platform=musiclink
  image_url: string | null; // artwork or photo
}
```

### Errors

Every error body is `{ "success": false, "error": "<message>" }`. Failed requests don't count toward your allowance.

| Status | Means | Do |
| --- | --- | --- |
| `400` | A parameter is missing or invalid; `error` names it. | Fix the request. Don't retry it as is. |
| `401` | The key is missing, wrong or revoked. | Send `Authorization: Bearer <key>` with an active key. |
| `404` | Nothing matched `q`. | Check the input. For a bare ID, send `platform` (and `type` for albums and artists). |
| `422` | Convert can't handle this `q`. | Send the same request to resolve. |
| `429` | Over a rate limit. | Wait the number of seconds in the `Retry-After` header, then retry. |
| `500` | Something failed on our side. | Retry after a few seconds. |

### Rate limits

Limits apply per account, shared by all of its keys.

| Plan | Per month | Per second | Per minute |
| --- | ---: | ---: | ---: |
| Free | 300 | 1 | 10 |
| Hobby | 5,000 | 2 | 60 |
| Developer | 15,000 | 3 | 120 |
| Pro | 50,000 | 5 | 200 |

Over the per-second limit: `429`, with `Retry-After: 1` and `"retryAfter": 1` in the body. Over the per-minute limit: the same with `60`. Over the monthly allowance: `429` with no `Retry-After` and your `plan` in the body; requests work again on the 1st of the next month. [Need more?](https://musiclink.one/pricing)

### Platforms

These are the keys in `platforms`. Links depend on each service's catalog and region, so not every item has every key. `isrc` and `upc` are codes, not keys in `platforms`: convert returns them with `to=isrc` or `to=upc`.

| Service | Key |
| --- | --- |
| MusicLink | `musiclink` |
| Spotify | `spotify` |
| ISRC | `isrc` |
| UPC | `upc` |
| Apple Music | `apple_music` |
| YouTube | `youtube` |
| YouTube Music | `youtube_music` |
| Deezer | `deezer` |
| TIDAL | `tidal` |
| SoundCloud | `soundcloud` |
| Amazon Music | `amazon_music` |
| Amazon Store | `amazon_store` |
| Pandora | `pandora` |
| Qobuz | `qobuz` |
| Yandex Music | `yandex` |
| Boomplay | `boomplay` |
| Anghami | `anghami` |
| Audiomack | `audiomack` |
| Shazam | `shazam` |
| JioSaavn | `jiosaavn` |
| Bandcamp | `bandcamp` |

---

## TypeScript SDK

A typed client for Node.js, so you call methods instead of building requests.

Source: https://musiclink.one/docs/sdk

```bash
npm install musiclink-api-sdk
```

```typescript
import { MusicLinkClient } from "musiclink-api-sdk";

const client = new MusicLinkClient({ apiKey: process.env.MUSICLINK_API_KEY });

const { data: [track] } = await client.resolveTrack("https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT");
track.platforms.apple_music;
```

It calls the v2 API: songs, albums and artists, with the same fields as [Responses](https://musiclink.one/docs#responses). Node 18 or newer; every method except `health()` needs a key.

### Resolve

```typescript
const { data } = await client.resolve("https://open.spotify.com/album/6N9PS4QXF1D0OWPk0Sxtb4");
if (data[0].type === "album") data[0].upc;

const { data: [artist] } = await client.resolveArtist("https://open.spotify.com/artist/0gxyHStUsqpMadRV0Di1Qt");
const { data: [song] } = await client.resolveTrack("4cOdK2wGLETKBW3PvgPWqT", { platform: "spotify" });
```

- `resolve(q, options?)` (Track | Album | Artist): Anything [resolve](https://musiclink.one/docs#send-a-request) takes: a link, an ISRC, a UPC, a MusicLink ID or link, or a bare ID with `platform`. The type is detected from `q`; check `item.type`.

- `resolveTrack · resolveAlbum · resolveArtist` (Track[] · Album[] · Artist[]): The same, with the type set. `resolveTrack` can return more than one song when versions share an ISRC.

- `options` (object): `type` (`resolve` only), `platform`, `include` (an array: `related.artists`, `related.album`, `platform_ids`) and `signal`, an `AbortSignal`.

Each result has the API's fields, with missing values as `null`, plus two helpers: `getLink("spotify")` and `getEmbedUrl({ layout, theme })` (layouts `full`, `compact`, `list`, `rail`, `slim`; themes `dark`, `light`, `artwork`; `EMBED_HEIGHTS` has each layout's iframe height).

Songs and albums already on MusicLink come from the cache, so a MusicLink ID or link is the quick way to look one up again:

```typescript
await client.resolveTrack("huUKtw-D");
await client.resolveTrack("https://musiclink.one/song/rick-astley/never-gonna-give-you-up");
```

### Convert

```typescript
const { data } = await client.convert("https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT", "isrc");
data.to.value; // "GBARL9300135"
```

- `convert(q, to, options?)` (Conversion): One answer from [convert](https://musiclink.one/docs#convert-one-link): `data.to.value`, `data.from` and `data.item`. Options: `type`, `platform`, `signal`.

- `convertTrack · convertAlbum · convertArtist` (Conversion): The same, with the type set, so `to` only accepts that type's values: `isrc` for songs, `upc` for albums.

### Client options

- `apiKey` (string): Your key from the [dashboard](https://musiclink.one/dashboard/keys).

- `timeoutMs` (number): Default: `30000`. A first lookup takes 10–15 seconds.

- `userAgent` (string): Your app's name and version, like `MyApp/1.0 (https://myapp.com)`. Sent ahead of the SDK's own.

- `baseUrl · webUrl · fetch`: For self-hosting, local development, or your own `fetch`.

### Errors

A failed request throws `MusicLinkError`, with `status` and `message`; `retryAfter` on `429` and `503`, `plan` when the monthly limit is reached. A timeout or network failure has `status` `0`. [What each status means](https://musiclink.one/docs#errors).

### Upgrading from 0.1

`query(q)` and `lookup(platform, id)` still work, through v2; prefer `resolveTrack`. The keyless `resolve(id)` and `resolveBySlug` are gone: pass the ID or the MusicLink link to `resolveTrack`. On results, `links` is now `platforms` and `public_id` is now `id`.
