FastSaverAPI moved. The API and dashboard now live at api.fastsaver.iowhat changed.

YouTube downloader API — from format lookup to a 4K file

Four endpoints make up the YouTube downloader API: read a video's formats and file sizes, download anything from 144p to 2160p (4K), take the audio track on its own, or search YouTube Music. Check the info call before you spend credits on a download.

Last updated

Endpoints
four — info, search, download, audio/tg-bot
Credits
2 info · 2 search · 15 download · 25 at 2K/4K · tg-bot audio 7 cached, 15 on a miss
Formats
audio, 144p → 2160p (4K)
Auth
X-Api-Key header

coverage

four endpoints, and what each one is for

YouTube does not go through the universal /fetch endpoint. The work is different: formats have to be enumerated, streams muxed, and the result is a file we produce rather than a link we forward.

EndpointMethodCreditsUse it when
/youtube/infoGET2Title, author, duration, thumbnails and every available format with its file size.
/youtube/searchGET2Tracks from YouTube Music — 10 per page, pages 1 to 3.
/youtube/downloadPOST15 · 25The file itself, at a resolution you choose, or the audio alone.
/youtube/audio/tg-botPOST7 · 15A Telegram file_id instead of bytes.

All four take the same X-Api-Key header. The GETs put parameters in the query string; the POSTs take a JSON body.

/youtube/audio/tg-bot is the one row with two prices, and the difference is worth budgeting for. If we already hold that video_id, you pay 7 credits and get a file_id back almost immediately. If we do not, the request falls through to a real download and bills the full 15 — the same as /youtube/download with format: "audio". A cold catalogue costs 15 a track; it is the second and later requests for the same track that cost 7.

the flow

check the formats before you spend fifteen credits

The correct order is info, then download. /youtube/info costs 2 credits and answers two things up front: which resolutions this video actually has, and how big each one is. A download that succeeds and hands you a four-gigabyte file nobody asked for still bills 15 — seven and a half times the lookup that would have talked you out of it.

GET https://api.fastsaver.io/v1/youtube/info 2 credits
request
curl -G "https://api.fastsaver.io/v1/youtube/info" \
  --data-urlencode "url=https://www.youtube.com/watch?v=HanBb8FonWs" \
  -H "X-Api-Key: fs_sk_•••••••••••"
200 OK · response
{
  "ok": true,
  "video_id": "HanBb8FonWs",
  "title": "Snails - Frogbass",
  "author": "DubstepGutter",
  "author_url": "https://www.youtube.com/channel/UCG6QEHCBfWZOnv7UVxappyw",
  "thumbnail": "https://i.ytimg.com/vi/HanBb8FonWs/sddefault.jpg",
  "duration": 234,
  "thumbnails": {
    "low": "https://i.ytimg.com/vi/HanBb8FonWs/mqdefault.jpg",
    "max": "https://i.ytimg.com/vi/HanBb8FonWs/maxresdefault.jpg"
  },
  "formats": [
    { "type": "video", "format": "144p", "filesize": 6967209 },
    { "type": "video", "format": "360p", "filesize": 21096358 },
    { "type": "video", "format": "720p", "filesize": 60448393 }
  ]
}

The -G and --data-urlencode matter. A watch URL carries its own ?v=, so pasting it raw into the query string splits it: the server reads url=https://www.youtube.com/watch plus a stray v parameter, finds no video id and errors. In code, let your HTTP client encode it — params= in requests, encodeURIComponent in JavaScript. A youtu.be/ID link has no query string and needs none of this.

filesize is in bytes. Render your quality picker from this array — a 4K button on a video that tops out at 720p is a support ticket.

Then ask for the file.

POST https://api.fastsaver.io/v1/youtube/download 15 credits · 25 at 2K/4K
request
curl -X POST "https://api.fastsaver.io/v1/youtube/download" \
  -H "X-Api-Key: fs_sk_•••••••••••" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://www.youtube.com/watch?v=HanBb8FonWs", "format": "1080p"}'
200 OK · response
{
  "ok": true,
  "video_id": "HanBb8FonWs",
  "duration": 234,
  "filename": "Snails - Frogbass (1080p, av1, youtube).mp4",
  "download_url": "https://api.fastsaver.io/v1/tunnel?id=3f7a1c9e-52b4-4d18-9f0a-6c2b7e51d8aa",
  "thumbnails": {
    "low": "https://i.ytimg.com/vi/HanBb8FonWs/mqdefault.jpg",
    "max": "https://i.ytimg.com/vi/HanBb8FonWs/maxresdefault.jpg"
  }
}

Two fields deserve a closer look.

  • filename arrives as title (format, codec, source).mp4, so av1 in the name is the codec you actually got. Fine for a Content-Disposition header; sanitise it before it touches a filesystem, because it carries whatever the uploader typed.
  • download_url is https://api.fastsaver.io/v1/tunnel?id=… — the same api.fastsaver.io host you just called, on the /v1/tunnel path, not a YouTube CDN link. The file is muxed on our side, so there is no signed googlevideo URL to hand you. The tunnel answers with a redirect to the file, so your client has to follow redirects (curl -L). Stream it straight through to storage or to your user.

reference

formats and what they cost

format is required and takes exactly one of these values. There is no "best" or "auto" — you pick, which means you control the bill.

formatWhat you getCredits
audioAudio track only, no video stream.15
144pSmallest file. Previews.15
240pLow bandwidth.15
360pWatchable on a phone.15
480pSD.15
720pHD. Sensible default.15
1080pFull HD.15
1440p2K.25
2160p4K.25

Only 2K and 4K break the flat rate, and not for the sake of tiering. A 4K download moves several times the data of a 1080p one and holds a worker longer while it does. We pass that through instead of averaging it into every request, so 720p users are not subsidising 4K users.

code

the whole flow in one function

Pick the highest resolution the video offers that fits a size budget, then download it. Two calls, one key, nothing to install on your side.

python · info → download → stream
import requests

BASE = "https://api.fastsaver.io/v1"
HEADERS = {"X-Api-Key": "fs_sk_•••••••••••"}
LADDER = ["2160p", "1440p", "1080p", "720p", "480p", "360p"]

def best_format(url, max_bytes=250_000_000):
    info = requests.get(f"{BASE}/youtube/info", params={"url": url},
                        headers=HEADERS, timeout=60).json()
    sizes = {f["format"]: f["filesize"] for f in info.get("formats", [])}
    for quality in LADDER:
        if quality in sizes and sizes[quality] <= max_bytes:
            return quality
    return "360p"

def download(url):
    quality = best_format(url)
    job = requests.post(f"{BASE}/youtube/download", headers=HEADERS,
                        json={"url": url, "format": quality}, timeout=300).json()
    if not job.get("ok"):
        raise RuntimeError(job.get("detail", "download failed"))
    with requests.get(job["download_url"], stream=True, timeout=300) as r:
        r.raise_for_status()
        with open(job["filename"], "wb") as fh:
            for chunk in r.iter_content(1 << 20):
                fh.write(chunk)
    return job["filename"]

print(download("https://www.youtube.com/watch?v=HanBb8FonWs"))

Note the timeouts. A 4K mux is not a 200 ms JSON call; a default five-second client timeout will abandon a request that was going to succeed. Stream the body rather than buffering gigabytes.

From a shell, the same lookup is one pipe:

shell
API="https://api.fastsaver.io/v1"
curl -s "$API/youtube/info?url=https://youtu.be/HanBb8FonWs" \
  -H "X-Api-Key: $FS_KEY" | jq '.formats[] | select(.format == "1080p")'

honesty

where the YouTube endpoints stop

  • Public videos only. If a signed-out browser cannot play it, the API cannot resolve it. Gated content returns an error, not a file.
  • A download_url lives about ten minutes. The id in https://api.fastsaver.io/v1/tunnel is held for 10 minutes and then dropped; after that the URL 404s with tunnel.not_found. Fetch the bytes in the same run; do not cache the string.
  • Not every video has every format. /youtube/info is the only honest answer to "is 4K available", and it costs 2 credits to ask.
  • Failures are cheap, not free. A private video, a dead link or a broken extraction still charges a flat 0.1 credits on any of the four endpoints, and answers 400. Nothing next to 15, but a retry loop over a video that will never resolve does bill.
  • Big downloads take real time. Budget for it in your client timeout and your worker queue.
  • Requests per minute follow the plan — 10 on Free, 900 on Mega. A 429 is a pacing signal: widen the gap between jobs rather than retrying the same one harder.
  • YouTube changes things. Extraction breaks on their schedule. We fix it behind the same endpoint; your code does not move.

What you download is your responsibility. Most of YouTube is somebody's copyrighted work, and an API key is not a licence.

faq

questions about the YouTube API

How do I download a YouTube video in 4K through an API?

POST to /youtube/download with {"url": "…", "format": "2160p"} and you get a download_url back. 2160p is 4K, 1440p is 2K, and both bill at 25 credits instead of 15. Not every video has a 4K master, so check /youtube/info first.

Can I get only the audio, without the video track?

Yes — POST /youtube/download with format: "audio". The YouTube to MP3 guide covers the Telegram path and the cost comparison.

How long does the download_url stay valid?

About ten minutes. It points at https://api.fastsaver.io/v1/tunnel?id=… — the same api.fastsaver.io host you called, on the /v1/tunnel path — and that id is held for 10 minutes, then dropped. After that the URL answers 404 tunnel.not_found. Pull the bytes in the same worker run; a URL cached yesterday will not resolve today.

Why do 1440p and 2160p cost 25 credits instead of 15?

Because they cost us more. A 4K stream is several times the bytes of a 1080p one and holds a worker longer. If your users watch on a phone, 1080p at 15 credits is the better trade.

Can I search YouTube Music and download the result in one flow?

Yes. /youtube/search returns 10 tracks per page, each with a video_id, for 2 credits. Feed that id to /youtube/audio/tg-bot — 7 credits if we already have the track, 15 if we have to fetch it first — or build a watch URL from it for /youtube/download. Pages 1–3 only, so 30 results per query.

Run a 4K download before you commit

Paste a video URL into the playground, pick a format and read the JSON. The free tier covers 66 standard downloads.