Response shape
One object, the same every time. A field that does not apply comes back as null rather than disappearing, so your parser never has to check whether a key exists.
Top level
| Field | Type | Notes |
|---|---|---|
platform | string | Which network the link belonged to: instagram, youtube, tiktok, facebook, vk, threads, twitter, reddit or pinterest |
type | string | video, image, album, or audio when you asked YouTube for mp3 |
title | string | null | The caption, or the video's title, when the post carries one |
author | string | null | Account or channel name, where the platform reports it |
thumbnail | string | null | Preview image |
duration | number | null | Length in seconds, where the platform reports it |
media | array | Always present, always at least one item |
Inside media
| Field | Type | Notes |
|---|---|---|
type | string | video, image or audio |
url | string | Direct link to one file. A video arrives with its audio already in it, so there is nothing to join afterwards. |
quality | string | null | The height VK encoded this rendition at, as a label like 1080p, or the format you asked YouTube for. null everywhere else. |
ext | string | null | mp4 or mp3 where the platform states it, null where it does not |
What is always filled in
platform, type and media always carry something. The other four do not: the same platform can answer with an author on one link and null on the next, so treat all four as optional and nothing will surprise you.
The one endpoint with a different shape
/v2/youtube/info downloads nothing, so it has nothing to put in media. It answers with the video's own facts instead: an id, an author_url, every thumbnail size, and a formats array listing each quality with its size in bytes. That body is on the YouTube page.
Writing against it
data = response.json()
if data["type"] == "album":
print(len(data["media"]), "files")
for item in data["media"]:
download(item["url"])