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.
- 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-Keyheader
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.
| Endpoint | Method | Credits | Use it when |
|---|---|---|---|
/youtube/info | GET | 2 | Title, author, duration, thumbnails and every available format with its file size. |
/youtube/search | GET | 2 | Tracks from YouTube Music — 10 per page, pages 1 to 3. |
/youtube/download | POST | 15 · 25 | The file itself, at a resolution you choose, or the audio alone. |
/youtube/audio/tg-bot | POST | 7 · 15 | A 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.
https://api.fastsaver.io/v1/youtube/info
2 credits
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_•••••••••••"
{
"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.
https://api.fastsaver.io/v1/youtube/download
15 credits · 25 at 2K/4K
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"}'
{
"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.
filenamearrives astitle (format, codec, source).mp4, soav1in the name is the codec you actually got. Fine for aContent-Dispositionheader; sanitise it before it touches a filesystem, because it carries whatever the uploader typed.download_urlishttps://api.fastsaver.io/v1/tunnel?id=…— the sameapi.fastsaver.iohost you just called, on the/v1/tunnelpath, 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.
format | What you get | Credits |
|---|---|---|
audio | Audio track only, no video stream. | 15 |
144p | Smallest file. Previews. | 15 |
240p | Low bandwidth. | 15 |
360p | Watchable on a phone. | 15 |
480p | SD. | 15 |
720p | HD. Sensible default. | 15 |
1080p | Full HD. | 15 |
1440p | 2K. | 25 |
2160p | 4K. | 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.
music
search youtube music, then deliver
/youtube/search queries music.youtube.com, not the main site, so results skew to
tracks rather than reaction videos and hour-long mixes. Ten per page; page is
required and accepts 1, 2 or 3. Thirty results is the ceiling.
https://api.fastsaver.io/v1/youtube/search
2 credits · 10 results
curl "https://api.fastsaver.io/v1/youtube/search?query=the%20weeknd&page=1" \
-H "X-Api-Key: fs_sk_•••••••••••"
{
"ok": true,
"page": 1,
"results": [
{
"video_id": "HgLfYfJtc8M",
"title": "The Weeknd - One Of The Girls",
"duration": "4:05",
"thumbnail": "https://i.ytimg.com/vi/HgLfYfJtc8M/mqdefault.jpg",
"thumbnail_max": "https://i.ytimg.com/vi/HgLfYfJtc8M/maxresdefault.jpg"
}
]
}
duration here is a display string like "4:05", not the integer seconds
that /youtube/info and /youtube/download return. Parse accordingly.
video_id is the join key: build a watch URL from it for
/youtube/download, or hand it to the
Telegram bot media API, which documents
file_id delivery in full.
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.
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:
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_urllives about ten minutes. Theidinhttps://api.fastsaver.io/v1/tunnelis held for 10 minutes and then dropped; after that the URL 404s withtunnel.not_found. Fetch the bytes in the same run; do not cache the string. - Not every video has every format.
/youtube/infois 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.