Turn a public post link from YouTube, TikTok, Instagram, Facebook, X, Xiaohongshu, Bilibili, Weibo, Douyin and 1000+ other sites into structured JSON and direct links to its videos, images and audio. Four synchronous endpoints: single post, page-by-page listing, subtitles and proxied YouTube downloads. Results come back in the same HTTP response; only successful requests are charged, from $0.004 per request.
| Endpoint | What it does | Price |
|---|---|---|
| POST /v1/media/extract | Extract a single post | $0.004 / request |
| POST /v1/media/playlist | List a channel, profile, playlist or hashtag | $0.02 / page |
| POST /v1/media/subtitles | Get subtitles (YouTube, Bilibili) | $0.004 / request |
| POST /v1/media/youtube-download | YouTube download links (proxied) | $0.012 / request |
Only successful requests are charged; failures (400 / 429 / 502 / 503 / 504) cost nothing. The playlist endpoint returns one page per call and bills per page. Downloading the returned files — YouTube proxy links included — is not billed again.
cURL: extract one post. Python: extract → pick the best quality → download with the media headers → merge separate audio and video with ffmpeg. Node.js: walk a profile page by page with next_cursor.
curl https://api.apimodels.app/v1/media/extract \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://www.tiktok.com/@creator/video/VIDEO_ID" }'A success returns { "code": 200, "msg": "success", "data": { ... } }. data.model is always media-downloader and data.endpoint names the endpoint (post / playlist / subtitles / youtube); the remaining fields are listed per endpoint below.
| Field | Required | Type | Description |
|---|---|---|---|
| x-apimodels-request-id | Yes | header | The id of this request. GET /v1/records/{id} returns what it was billed. |
| x-apimodels-cost | No | header | On success, the USD amount deducted for this request (after any account discount). |
Extract a single post · $0.004 per request
One public post from 1000+ sites (YouTube, TikTok, Instagram, Facebook, X, Xiaohongshu, Bilibili, Weibo, Douyin and more). Short links such as youtu.be and vt.tiktok.com work as-is. Returns the caption, author, stats and every media file with its available qualities.
| Field | Required | Type | Description |
|---|---|---|---|
| url | Yes | string | Link to one post. Short links (youtu.be, vt.tiktok.com and similar) are accepted as-is. |
curl https://api.apimodels.app/v1/media/extract \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://www.tiktok.com/@creator/video/VIDEO_ID" }'Structure from a real call, values and links replaced with placeholders; fields a post does not have are omitted.
{
"code": 200,
"msg": "success",
"data": {
"model": "media-downloader",
"endpoint": "post",
"site": "youtube",
"id": "VIDEO_ID",
"title": "Video title",
"text": "Caption or description of the post",
"post_url": "https://www.youtube.com/watch?v=VIDEO_ID",
"author": { "username": "creator", "display_name": "Creator Name" },
"stats": { "view_count": 1024 },
"medias": [
{
"media_type": "video",
"resource_url": "https://...",
"preview_url": "https://...",
"duration": 19,
"variants": [
{
"quality": 1080,
"quality_label": "1080p",
"video_url": "https://...",
"video_ext": "mp4",
"video_filesize": 5242880,
"audio_url": "https://...",
"audio_ext": "m4a"
},
{
"quality": 360,
"quality_label": "360p",
"video_url": "https://...",
"video_ext": "mp4",
"is_default": true
}
]
},
{
"media_type": "audio",
"resource_url": "https://...",
"duration": 19
}
]
}
}| Field | Required | Type | Description |
|---|---|---|---|
| site | Yes | string | The platform the post came from, e.g. youtube. |
| id | No | string | The post id on that platform. |
| title / text | No | string | Title and caption or description, when the platform has them. |
| post_url | No | string | Canonical link to the post. |
| created_at | No | string | Publish time as the platform reports it; the format varies by site. |
| author | No | object | username and display_name (sometimes id). |
| stats | No | object | Counts the platform exposes, e.g. view_count. |
| medias[] | Yes | array | One entry per file in the post; fields below. |
| Field | Required | Type | Description |
|---|---|---|---|
| media_type | Yes | string | video | image | audio | live | file |
| resource_url | No | string | Direct link to the file. Short-lived — download right away. |
| preview_url | No | string | Cover or thumbnail image. |
| duration | No | number | Length in seconds, for video and audio. |
| headers | No | object | Request headers to send when downloading this file (for example Referer). Present only when needed. |
| variants[] | No | array | Available qualities: quality (number, e.g. 1080), quality_label (e.g. "1080p"), video_url, video_ext, video_filesize (bytes, when known), audio_url / audio_ext (only when the audio is a separate track), is_default. |
List a channel, profile, playlist or hashtag · $0.02 per page
One page per call. Pass next_cursor back as cursor for the next page and stop when has_more is false. Supported: YouTube channels, Shorts, playlists and hashtags; Instagram profiles and hashtags; X; TikTok profiles and hashtags; Douyin; Bilibili; Weibo.
| Field | Required | Type | Description |
|---|---|---|---|
| url | Yes | string | Link to a profile, channel, playlist or hashtag. |
| cursor | No | string | The next_cursor from the previous page. Leave it out for the first page. |
curl https://api.apimodels.app/v1/media/playlist \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://www.youtube.com/@channel/videos" }'
# next page: add "cursor": "<next_cursor from the previous response>"{
"code": 200,
"msg": "success",
"data": {
"model": "media-downloader",
"endpoint": "playlist",
"site": "youtube",
"profile": { "username": "@channel" },
"posts": [
{
"id": "VIDEO_ID",
"title": "Video title",
"created_at": "3 days ago",
"medias": [
{
"media_type": "video",
"resource_url": "https://...",
"preview_url": "https://...",
"duration": 1215
}
]
}
],
"has_more": true,
"next_cursor": "NEXT_CURSOR"
}
}| Field | Required | Type | Description |
|---|---|---|---|
| site | Yes | string | The platform. |
| posts[] | Yes | array | The posts on this page, shaped like a single-post result but usually with fewer fields (for example no variants). For every quality of one entry, call /v1/media/extract on it. |
| has_more | Yes | boolean | Whether another page exists. |
| next_cursor | No | string | The cursor for the next page. |
| profile | No | object | username, display_name, avatar_url, post_count — whichever the platform provides. |
Paging: send the same url again with cursor, until has_more is false. Every page is a $0.02 request, so a page limit in your loop doubles as a spending limit.
Get subtitles (YouTube, Bilibili) · $0.004 per request
Every subtitle track on a YouTube or Bilibili video. YouTube offers srt, vtt and json3; Bilibili returns json (BCC). Auto-generated tracks say "(auto-generated)" in language_name. Links are short-lived (Bilibili about 30 minutes).
| Field | Required | Type | Description |
|---|---|---|---|
| url | Yes | string | A YouTube or Bilibili video link. |
curl https://api.apimodels.app/v1/media/subtitles \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://www.youtube.com/watch?v=VIDEO_ID" }'{
"code": 200,
"msg": "success",
"data": {
"model": "media-downloader",
"endpoint": "subtitles",
"site": "youtube",
"id": "VIDEO_ID",
"title": "Video title",
"duration": 19,
"thumbnail_url": "https://...",
"subtitles": [
{
"language_name": "English",
"language_tag": "en",
"urls": [
{ "format": "srt", "url": "https://..." },
{ "format": "vtt", "url": "https://..." },
{ "format": "json3", "url": "https://..." }
]
}
]
}
}| Field | Required | Type | Description |
|---|---|---|---|
| site / id / title | No | string | Platform, video id and title. |
| duration | No | number | Video length in seconds. |
| thumbnail_url | No | string | Thumbnail image. |
| subtitles[] | Yes | array | One entry per track: language_name (auto-generated tracks say "(auto-generated)"), language_tag (e.g. en), urls[] { format, url }. |
Formats: YouTube offers srt, vtt and json3; Bilibili returns json (BCC). Subtitle links are short-lived — about 30 minutes on Bilibili — so fetch them right away.
YouTube download links (proxied) · $0.012 per request
YouTube files served through a temporary proxy: resource_proxy_url is a complete lower-quality file or the audio, variants carry video_proxy_url / audio_proxy_url up to 1080p (separate tracks to merge). Links last at most 1 hour and support HTTP Range, so downloads can resume. Not available for files over 3 GiB.
| Field | Required | Type | Description |
|---|---|---|---|
| url | Yes | string | A youtube.com or youtu.be link. |
curl https://api.apimodels.app/v1/media/youtube-download \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://youtu.be/VIDEO_ID" }'{
"code": 200,
"msg": "success",
"data": {
"model": "media-downloader",
"endpoint": "youtube",
"site": "youtube",
"id": "VIDEO_ID",
"title": "Video title",
"medias": [
{
"media_type": "video",
"duration": 19,
"resource_proxy_url": "https://...",
"variants": [
{
"quality": 1080,
"quality_label": "1080p",
"video_ext": "mp4",
"video_proxy_url": "https://...",
"audio_ext": "m4a",
"audio_proxy_url": "https://..."
}
]
}
]
}
}| Field | Required | Type | Description |
|---|---|---|---|
| medias[].resource_proxy_url | No | string | A complete lower-quality file, or the audio. |
| variants[].video_proxy_url | No | string | The video track for that quality, up to 1080p. |
| variants[].audio_proxy_url | No | string | The matching audio track; merge it with the video track for a complete file. |
| HTTP | Meaning | Charged | What to do |
|---|---|---|---|
| 400 | The content cannot be fetched or the request is wrong: error_code such as content_deleted, unsupported_site or invalid_url; a missing or non-http(s) url is also a 400. | No | Check retryable: true means retry, false means change the link |
| 401 | Chave API ausente ou inválida | No | Check the Authorization header |
| 402 | Insufficient credits | No | Top up and retry |
| 429 | Rate limited | No | Wait briefly and retry |
| 502 / 503 / 504 | Temporary error or timeout (youtube-download’s proxy_unavailable is a 503 too) | No | Retry |
A 400 body:
{
"code": 400,
"msg": "This content has been deleted or doesn't exist.",
"error_code": "content_deleted",
"retryable": false
}ffmpeg -i video.mp4 -i audio.m4a -c copy out.mp4Use the extensions from video_ext / audio_ext; if the video is webm, write out.mkv instead. A variant with only video_url is already a complete file and needs no merging.
POST {"url": "<post link>"} to https://api.apimodels.app/v1/media/extract with Authorization: Bearer <API key>. The answer is synchronous: data.medias[] holds each file with a resource_url and, for videos, variants[] per quality. Download the file you want right away and send medias[].headers with it when present. For YouTube links up to 1080p that can resume after a dropped connection, call /v1/media/youtube-download instead ($0.012 per request); extract is $0.004 per request.
Call /v1/media/playlist with the channel, profile, playlist or hashtag URL, then call it again with "cursor" set to next_cursor until has_more is false. Each call returns one page and costs $0.02. Page entries carry fewer fields than a single-post result, so call /v1/media/extract ($0.004) on a post when you need all of its qualities.
POST the video link to /v1/media/subtitles ($0.004 per request). Each track in data.subtitles[] lists urls[] by format: srt, vtt or json3 on YouTube, json (BCC) on Bilibili. Auto-generated tracks say "(auto-generated)" in language_name. Fetch the file right away, because the links expire (about 30 minutes on Bilibili).
None of them are charged. A 400 carries an error_code (content_deleted, unsupported_site, invalid_url) and a retryable flag; retry only when retryable is true. 429 and 502 / 503 / 504 are temporary, so retry after a short wait, including a youtube-download 503 with error_code proxy_unavailable. 401 means the API key is missing or wrong, 402 means the balance is too low.