Home > Blog > How to Download TikTok Audio (MP3) via API
Downloads

How to Download TikTok Audio from a Video via API

By PrimeApi·August 15, 2026·8 min read·Updated August 15, 2026

A TikTok post carries two separate media assets: the rendered video and the sound attached to it. When the audio is what you actually want - archiving the tracks behind a set of posts, feeding an audio fingerprinting job, or building an internal library of the sounds a brand has used - pulling the whole MP4 and discarding the picture is wasted bandwidth. PrimeApi keeps the two apart: download-music turns a post URL into a direct audio link, download-video does the same for the clip, and music-info tells you what the sound actually is. Every field named below comes from live responses captured against the production API.

The smallest response in the catalogue

download-music takes one required parameter, url, which is the full TikTok post link, URL-encoded. There are no optional parameters, no cursor and no page size, because there is nothing to page. What comes back is a single field:

{
  "play": "https://..."
}

That is the entire payload. No title, no artist, no duration, no bitrate, no music ID. The response is deliberately tiny, which makes this one of the cheapest calls to run in bulk, but it also means you cannot label what you have downloaded from this call alone. Metadata comes from a different endpoint, covered further down.

Calling download-music

The base URL is https://api.primeapi.co/ and authentication is a single header, X-PrimeAPI-Key, exactly as described in the API documentation. Remember to percent-encode the post URL you pass in - an unencoded ? or & in a share link will truncate your query string.

curl

curl -s "https://api.primeapi.co/download-music?url=https%3A%2F%2Fwww.tiktok.com%2F%40username%2Fvideo%2F7312069407369366830" \
  -H "X-PrimeAPI-Key: YOUR_API_KEY"

Node.js (Axios)

const axios = require("axios");
const fs = require("fs");

const KEY = "YOUR_API_KEY";

// Map what the CDN says it sent to a sane file extension.
const EXT = {
  "audio/mpeg": "mp3",
  "audio/mp4": "m4a",
  "video/mp4": "m4a"
};

async function downloadAudio(postUrl, baseName) {
  // 1) Resolve the post URL into a direct audio link
  const res = await axios.get("https://api.primeapi.co/download-music", {
    params: { url: postUrl },
    headers: { "X-PrimeAPI-Key": KEY }
  });

  console.log("balance:", res.headers["x-primeapi-balance"]);

  const play = res.data && res.data.play;
  if (!play) throw new Error("No play field in response");

  // 2) Fetch the file yourself - this step costs no credits
  const file = await axios.get(play, { responseType: "stream" });
  const type = (file.headers["content-type"] || "").split(";")[0];
  const out = baseName + "." + (EXT[type] || "bin");

  await new Promise((resolve, reject) => {
    const w = fs.createWriteStream(out);
    file.data.pipe(w);
    w.on("finish", resolve);
    w.on("error", reject);
  });

  console.log("saved", out, "as", type);
  return out;
}

downloadAudio(
  "https://www.tiktok.com/@username/video/7312069407369366830",
  "sound"
).catch(e => console.error(e.response ? e.response.data : e.message));

Python (Requests)

import requests

KEY = "YOUR_API_KEY"
EXT = {"audio/mpeg": "mp3", "audio/mp4": "m4a", "video/mp4": "m4a"}

def download_audio(post_url, base_name):
    # 1) Resolve the post URL into a direct audio link
    res = requests.get(
        "https://api.primeapi.co/download-music",
        params={"url": post_url},
        headers={"X-PrimeAPI-Key": KEY},
        timeout=20,
    )
    print("balance:", res.headers.get("X-PrimeAPI-Balance"))
    res.raise_for_status()

    play = res.json().get("play")
    if not play:
        raise RuntimeError("No play field in response")

    # 2) Fetch the file yourself - no credits are spent here
    with requests.get(play, stream=True, timeout=60) as f:
        f.raise_for_status()
        ctype = f.headers.get("Content-Type", "").split(";")[0]
        out = base_name + "." + EXT.get(ctype, "bin")
        with open(out, "wb") as fh:
            for chunk in f.iter_content(chunk_size=8192):
                fh.write(chunk)

    print("saved", out, "as", ctype)
    return out

if __name__ == "__main__":
    download_audio(
        "https://www.tiktok.com/@username/video/7312069407369366830",
        "sound",
    )

What the play field actually is

It is a direct link to a file on TikTok's own content network. The API does not stream binary audio back through the JSON response, and it does not base64-encode anything - that two-step split is what keeps the call fast and the payload one line long.

The word MP3 in the title is how people search for this, but it is worth being precise: you get whatever TikTok is serving, and the safe way to find out is to look at the Content-Type header on your own fetch rather than trusting the file extension in the URL. That is what the EXT lookup does in both samples above. If a downstream tool genuinely requires MP3 - a podcast pipeline, a speech-to-text service with a narrow input list - transcode locally after saving instead of assuming the source is already in that container.

Expiry and re-hosting

These links are signed and time-limited. That has three practical consequences. Do not store the URL in a database as if it were a permanent asset location. Do not put it in an email, a Slack message or a report that someone might open the next morning. And do not hand it straight to a browser in your own UI, because the request that eventually fires may be long after the link stopped working.

The correct shape is to fetch server-side straight away and re-host on your own storage. Persist your own object key alongside the source post URL and, ideally, the sound's musicId, so you can always re-run the call for a fresh link. Re-hosting also insulates you from hotlink protection, gives you a content type you control, and means your users are not pulling media from a third-party domain on every page view. The second fetch is a plain CDN request and does not consume credits, so re-hosting costs you storage, not balance.

download-music compared with download-video

The two download endpoints look interchangeable and are not. Both take the same required url, both return links rather than files, and there the similarity ends.

 download-musicdownload-video
Required parameterurlurl
Optional parametersnonenone
Fields returnedplayplay, play_watermark
What play isThe sound attached to the postThe clip with no watermark
play_watermarknot returnedThe clip exactly as published, overlay included
Credits per call11

The important difference is not the field count, it is what the audio represents. download-music gives you the sound object the post is filed under. The audio inside a download-video file is the published mix - voiceover, sound effects and the track together, as viewers hear it. Where a creator recorded an original sound in-app those are effectively the same recording. Where someone has talked over a licensed track, they are not, and picking the wrong one will quietly ruin a fingerprinting or transcription job. Decide which you want before you write the pipeline. The walkthrough on downloading TikTok videos without a watermark covers the video side in full.

If you need both assets, that is two calls and two credits. If you only need the mixed audio, one download-video call plus a local ffmpeg pass strips the picture for a single credit - the trade being that you get the mix rather than the sound.

Labelling the audio with music-info

Since download-music returns nothing but a link, an archive built on it alone is a folder of anonymous files. music-info fixes that, but it is keyed by musicId, not by a post URL, so there is one hop in between: read music.id out of any video record. In post-detail it sits at itemInfo.itemStruct.music.id, and on feed-shaped endpoints every entry of itemList carries the same music.id.

With that number, music-info returns a musicInfo object holding music, artist, artists and stats, alongside a shareMeta block and the usual statusCode, status_code and status_msg. The fields worth storing:

FieldMeaning
musicInfo.music.idThe musicId - your deduplication key
musicInfo.music.titleTrack name
musicInfo.music.authorNameCredited artist name
musicInfo.music.albumAlbum, where the sound is a release
musicInfo.music.durationLength of the sound in seconds
musicInfo.music.shoot_durationPortion creators may film over
musicInfo.music.playUrlDirect link to the catalogue track
musicInfo.music.coverThumb / coverMedium / coverLargeArtwork at three sizes
musicInfo.music.originalCreator-recorded sound rather than a catalogue track
musicInfo.music.privateSound is not openly available
musicInfo.music.tt2dspHolds tt_to_dsp_song_infos, the mapping to streaming catalogues
musicInfo.artistProfile block: id, uniqueId, nickname, secUid, signature, avatars
musicInfo.stats.videoCountHow many videos use this sound

Note that playUrl is itself a second route to the audio. If your pipeline starts from a sound rather than from a post - a trending-sounds board, say - you already hold the link and do not need download-music at all. The distinction is the same one as above: playUrl is the catalogue track, download-music resolves from a specific post. Our guide to getting TikTok sound and music info goes through the whole record field by field.

The licensing reality

This is the part most downloader tutorials skip. Being able to fetch a file is not permission to use it. The music record carries four flags that people routinely mistake for a rights answer: original, isCopyrighted, is_commerce_music and is_unlimited_music. They describe how TikTok classifies a sound inside its own catalogue - whether it came from a creator or a label, whether it is cleared for commercial accounts, whether the usable portion is capped. None of them says anything about what you may do with the file on your own servers.

The practical reading is straightforward. A track licensed for use in the app is licensed for that - not for your advert, your client's showreel, your podcast bed or a re-upload elsewhere. If tt2dsp maps the sound to streaming catalogues, you are looking at a commercial release and the rights holder is the only party who can clear it. If original is true, the creator recorded it, and the creator is who you ask. Either way, TikTok's Terms of Service govern access to the platform, and PrimeApi is an independent, unofficial service that is not affiliated with or endorsed by TikTok or ByteDance. The API supplies the technical means; it does not supply legal clearance.

Credits, limits and errors

Every call costs 1 credit and returns your remaining balance in X-PrimeAPI-Balance. The follow-up media fetch is free. The default rate limit is 100 requests per minute, responses are real-time with no caching, and average response time is around one second. New accounts get 50 free credits, which is enough to test a batch end to end before you look at the credit bundles.

Failures come back as JSON with a message field rather than as an exception: a missing header gives "Please sign up to primeapi.co", a wrong key gives "PrimeAPI-Key is not available", exceeding the per-minute limit gives the rate limit message, and an empty balance gives "Your balance has been exhausted...". Check for play before you index into the response, as both code samples do, so a text error never gets written to disk as an audio file.

A sane batch shape

One rule saves most of the cost in a bulk archiving job: deduplicate by musicId before you download anything. A hundred posts riding the same trending sound need one audio fetch, not a hundred. Collect the video records first, group them by music.id, call download-music once per distinct sound with any one of its post URLs, and store the mapping from post to file on your side. If you are working the other way round and want the full spread of a track, the guide to finding every video using a TikTok sound covers paging that catalogue. When you are ready to run it for real, create an account and the free credits will cover a first pass.

Frequently asked questions

Does download-music return an MP3 file?

No. It returns JSON with a single field, play, which is a direct link to the audio hosted on TikTok's CDN. You fetch that link yourself in a second step. Do not hard-code an .mp3 extension either - read the Content-Type header on your own fetch and, if a downstream tool needs a guaranteed format, transcode the file locally after you have saved it.

How long does the returned audio URL stay valid?

Treat it as short-lived. The link is signed and time-limited, so it is fine to fetch immediately and wrong to store in a database, email to a user or hand to a browser hours later. Download it server-side, re-host it on your own storage, and keep the post URL or musicId so you can call the endpoint again if you ever need a fresh link.

What is the difference between download-music and download-video?

They take the same required url parameter and return different things. download-music answers with one field, play, for the sound attached to the post. download-video answers with two, play for the clip without the watermark and play_watermark for the copy exactly as published. The audio inside the video is the published mix, which is not always the same recording as the sound.

How do I get the title and artist of the audio?

Not from download-music - that response is only a link. Read music.id out of any video record, for example itemInfo.itemStruct.music.id in post-detail, then call music-info with it. That returns musicInfo.music with title, authorName, album and duration, plus a musicInfo.artist block and musicInfo.stats.videoCount.

Can I publish the audio I download?

A file link is not a licence. The flags on the music record - original, isCopyrighted, is_commerce_music, is_unlimited_music - describe how TikTok classifies the sound in its own catalogue, not what you are allowed to do with it. Commercial tracks are cleared for use inside the app, not for your podcast, advert or client edit. Clear rights with the creator or the rights holder first.

How many credits does an audio download cost?

One credit per API call, the same as every PrimeApi endpoint, with the remaining balance in the X-PrimeAPI-Balance response header. Fetching the actual file from the returned link is a direct CDN request and costs nothing. New accounts start with 50 free credits and the default rate limit is 100 requests per minute.

Start building with the PrimeApi TikTok API
50 free credits when you sign up. No card required - you only pay when you need more.

← Back to the PrimeApi Blog