Документация
Один base URL, bearer-авторизация, JSON в каждом ответе. В продакшене за десять минут.
base urlhttps://api.saveapi.org/v1
Один GET на ссылку. Отправьте любую публичную ссылку на пост в /v1/download и читайте medias[] — каждая запись это прямая ссылка на файл в CDN самого источника, в том же ответе. Ни второго запроса, ни параметра формата: там, где источник отдаёт несколько готовых вариантов, все они приходят вместе в formats[].
curl -s -G "https://api.saveapi.org/v1/download" \
-H "Authorization: Bearer sk_live_xxxx" \
--data-urlencode "url=https://www.tiktok.com/@zachking/video/6768504823336815877"Официальные SDK
Лёгкие клиенты для Python и JavaScript/TypeScript: те же эндпоинты и форма ответа, с типами; ошибки приходят как SaveAPIError со стабильным кодом. Повторяется только то, что может помочь повтор — UPSTREAM_TIMEOUT, UPSTREAM_ERROR и RATE_LIMITED после Retry-After; приватные, удалённые и неподдерживаемые ссылки — никогда.
from saveapi import SaveAPI, SaveAPIError
api = SaveAPI("sk_live_...") # or set SAVEAPI_KEY
try:
post = api.download("https://www.tiktok.com/@zachking/video/6768504823336815877")
print(post["medias"][0]["url"])
except SaveAPIError as error:
print(error.code) # PRIVATE_CONTENT, MEDIA_NOT_FOUND, ...import { SaveAPI, SaveAPIError } from "saveapi";
const api = new SaveAPI({ apiKey: "sk_live_..." }); // or SAVEAPI_KEY
try {
const post = await api.download("https://www.tiktok.com/@zachking/video/6768504823336815877");
console.log(post.medias[0].url);
} catch (error) {
if (error instanceof SaveAPIError) console.log(error.code);
}Лицензия MIT, с примерами Telegram-бота и скачивания файла: github.com/akhroruz/saveapi-sdk
Кредиты за запрос
Каждый endpoint говорит свою цену до вызова. Загрузки тарифицируются за успешный результат; всё остальное бесплатно.
Тысяча кредитов стоит $0.09 на Pro и $0.066 на Mega — доля цента за обычную загрузку.
Точная сумма приходит в каждом ответе в credits.spent, а остаток — в заголовке X-Credits-Remaining. Вести свой учёт не нужно.
Коды ошибок
Каждая ошибка приходит в одном и том же конверте. Ветвитесь по code, а не по message — текст может меняться, коды нет.
{
"success": false,
"error": {
"code": "INVALID_URL",
"message": "The url must be a public http(s) link to a post"
}
}Эндпоинты
Выберите эндпоинт слева. Каждый — обычный GET с ключом в заголовке: без опроса статуса и без job id.
/v1/download
от 1.5 кредитаВозвращает прямые медиа-URL, а также метаданные автора и подписи.
urlобязательныйstringlimit_mbнеобязательныйnumberfull_metaнеобязательныйbooleancurl -s -G "https://api.saveapi.org/v1/download" \
-H "Authorization: Bearer sk_live_xxxx" \
--data-urlencode "url=https://www.tiktok.com/@zachking/video/6768504823336815877"{
"success": true,
"platform": "tiktok",
"type": "video",
"source_url": "https://www.tiktok.com/@zachking/video/6768504823336815877",
"video_id": "6768504823336815877",
"medias": [
{
"type": "video",
"url": "https://v16m.tiktokcdn-us.com/...",
"ext": "mp4",
"quality": null,
"width": 0,
"height": 0,
"size_mb": 4.19,
"watermark": false
}
],
"music": {
"type": "audio",
"url": "https://v16-ies-music.tiktokcdn-us.com/...",
"ext": "mp3",
"quality": null,
"width": 0,
"height": 0,
"size_mb": null,
"watermark": null
},
"meta": {
"title": "They rejected my application to Hogwarts but I still found a way to be a wizard. 🧹#illusion #magic #harrypotter",
"text": "They rejected my application to Hogwarts but I still found a way to be a wizard. 🧹#illusion #magic #harrypotter",
"author": "Zach King",
"author_url": "https://www.tiktok.com/@zachking",
"thumbnail": "https://p19-common-sign.tiktokcdn-us.com/...",
"duration": 18,
"views": 2382320428,
"published_at": 1575915337,
"username": "zachking",
"author_avatar": "https://p16-common-sign.tiktokcdn-us.com/...",
"author_verified": null,
"likes": 63400000,
"comments": 296700,
"shares": 2400000,
"saves": 1900000,
"location": null,
"region": "US",
"music": {
"title": "original sound",
"author": "Zach King",
"duration": 18,
"cover": "https://p16-common-sign.tiktokcdn-us.com/...",
"original": true
}
},
"formats": [
{ "format": "nowm", "label": "No watermark", "type": "video", "size_mb": 4.19, "exact": true, "watermark": false, "url": "https://v16m.tiktokcdn-us.com/..." },
{ "format": "hd", "label": "HD, no watermark", "type": "video", "size_mb": 3.0, "exact": true, "watermark": false, "url": "https://v16-notes.tiktokcdn-us.com/..." },
{ "format": "wm", "label": "With watermark", "type": "video", "size_mb": 4.25, "exact": true, "watermark": true, "url": "https://v16m.tiktokcdn-us.com/..." },
{ "format": "mp3", "label": "Audio (mp3)", "type": "audio", "size_mb": null, "exact": false, "url": "https://v16-ies-music.tiktokcdn-us.com/..." }
],
"recommended_format": "nowm",
"credits": { "spent": 1.5, "remaining": 99988.5 }
}curl -s -G "https://api.saveapi.org/v1/download" \
-H "Authorization: Bearer sk_live_xxxx" \
--data-urlencode "url=https://www.tiktok.com/@zachking/video/6768504823336815877"Авторизация
Каждый запрос несёт секретный ключ в заголовке Authorization. Ключи не истекают, но их можно отозвать и перевыпустить в любой момент.
Authorization: Bearer sk_live_xxxxxxxxxxxxДля клиентов, которые не могут задать заголовок Authorization, принимается и X-API-Key: sk_live_….
Ответ
Каждый успешный запрос возвращает одну и ту же структуру. В medias[] лежат прямые файлы — всегда хотя бы один, несколько для карусели. В meta приходят заголовок, автор, обложка и длительность, если источник их публикует, а credits показывает стоимость запроса и остаток.
{
"success": true,
"platform": "tiktok",
"type": "video",
"source_url": "https://www.tiktok.com/@zachking/video/6768504823336815877",
"video_id": "6768504823336815877",
"medias": [
{
"type": "video",
"url": "https://v16m.tiktokcdn-us.com/...",
"ext": "mp4",
"quality": null,
"width": 0,
"height": 0,
"size_mb": 4.19,
"watermark": false
}
],
"music": {
"type": "audio",
"url": "https://v16-ies-music.tiktokcdn-us.com/...",
"ext": "mp3",
"quality": null,
"width": 0,
"height": 0,
"size_mb": null,
"watermark": null
},
"meta": {
"title": "They rejected my application to Hogwarts but I still found a way to be a wizard. 🧹#illusion #magic #harrypotter",
"text": "They rejected my application to Hogwarts but I still found a way to be a wizard. 🧹#illusion #magic #harrypotter",
"author": "Zach King",
"author_url": "https://www.tiktok.com/@zachking",
"thumbnail": "https://p19-common-sign.tiktokcdn-us.com/...",
"duration": 18,
"views": 2382320428,
"published_at": 1575915337,
"username": "zachking",
"author_avatar": "https://p16-common-sign.tiktokcdn-us.com/...",
"author_verified": null,
"likes": 63400000,
"comments": 296700,
"shares": 2400000,
"saves": 1900000,
"location": null,
"region": "US",
"music": {
"title": "original sound",
"author": "Zach King",
"duration": 18,
"cover": "https://p16-common-sign.tiktokcdn-us.com/...",
"original": true
}
},
"formats": [
{ "format": "nowm", "label": "No watermark", "type": "video", "size_mb": 4.19, "exact": true, "watermark": false, "url": "https://v16m.tiktokcdn-us.com/..." },
{ "format": "hd", "label": "HD, no watermark", "type": "video", "size_mb": 3.0, "exact": true, "watermark": false, "url": "https://v16-notes.tiktokcdn-us.com/..." },
{ "format": "wm", "label": "With watermark", "type": "video", "size_mb": 4.25, "exact": true, "watermark": true, "url": "https://v16m.tiktokcdn-us.com/..." },
{ "format": "mp3", "label": "Audio (mp3)", "type": "audio", "size_mb": null, "exact": false, "url": "https://v16-ies-music.tiktokcdn-us.com/..." }
],
"recommended_format": "nowm",
"credits": { "spent": 1.5, "remaining": 99988.5 }
}Один ключ есть не всегда. formats[] появляется только там, где источник сам отдаёт несколько готовых вариантов — сегодня это VK, TikTok и Likee — и в каждой записи лежит прямая ссылка и точный размер, так что нужный вариант вы выбираете у себя. Второго запроса и параметра формата нет. На остальных платформах ключа просто нет, и ответом служит medias[]:
"formats": [
{ "format": "mp4_144", "label": "144p", "type": "video", "size_mb": 0.76, "url": "https://..." },
{ "format": "mp4_480", "label": "480p", "type": "video", "size_mb": 7.9, "url": "https://..." },
{ "format": "mp4_1080", "label": "1080p", "type": "video", "size_mb": 36.37, "url": "https://..." }
],
"recommended_format": "mp4_1080"Заголовки ответа
В каждом ответе есть ваш тариф, остаток баланса и окно rate limit. Читайте X-Credits-Remaining, чтобы предупредить себя до того, как кредиты кончатся.
X-Plan: pro
X-Credits-Remaining: 99988
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59Rate limit
Лимит на ключ, в минуту. У каждого ключа свой лимит — если один сервис горячее другого, разведите трафик по ключам.
При превышении приходит 429 RATE_LIMITED с заголовком Retry-After — подождите столько секунд и отправьте снова. Отклонённые вызовы не списываются.
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0Кредиты и оплата
Успешная загрузка стоит 1.5 кредита — история Instagram 5, Rutube 3, потому что обе обходятся нам дороже. Остальные endpoint'ы бесплатны. Кредиты покупаются пакетами и действуют 30 дней с покупки. Бесплатные 1 000 при регистрации не сгорают.
Ссылка, в которой источник отказал — закрытая, удалённая или без медиа, — стоит 0.1 кредита: поиск был сделан и вернулся пустым. Всё остальное бесплатно: битые ссылки, неподдерживаемые сайты, лимиты, таймауты источника и наши собственные ошибки.
Тарифы
Списываем за каждый запрос: загрузка 1.5 кредита, история Instagram 5, Rutube 3. Ссылка, в которой источник отказал — закрытая или удалённая, — 0.1. Платные кредиты действуют 30 дней с момента покупки.
Застряли или чего-то не хватает?