Справочник TikTok Python SDK
Клиент TikTok в Python SDK Socialift работает с TikTok Open API v2 (Login Kit, профиль, список видео, Content Posting API) и TikTok API for Business (метрики аккаунта, модерация комментариев). Все методы асинхронные и принимают токен пользователя аргументом, поэтому один клиент обслуживает многих авторов. Ниже — каждый метод по задачам, лимиты взяты из документации TikTok.
from socialift import TikTokМетодов: 26по версии socialift 1.3.0Обновлено:
Как создать клиент TikTok?
Создайте приложение на developers.tiktok.com и скопируйте его Client key и Client secret. Передайте их как client_key и client_secret или вызовите TikTok.from_env() — он читает переменные окружения TIKTOK_CLIENT_KEY и TIKTOK_CLIENT_SECRET. Лицензионный ключ Socialift берётся из SOCIALIFT_LICENSE_KEY (или аргумента license_key=).
Клиент не хранит токены: каждый метод принимает token аргументом. Access token действует 24 часа, refresh token — 365 дней, и при обновлении TikTok может вернуть новый refresh token — каждый раз перезаписывайте значение в базе.
По умолчанию login_url() запрашивает scope из DEFAULT_SCOPES (user.info.basic, user.info.profile, user.info.stats, video.list, video.upload, video.publish); если нужно меньше — передайте scopes=. Методам Business API (business_account, comments и др.) нужен ещё business_id — задайте его один раз через TikTok(..., business_id=open_id) или передавайте в каждый вызов.
Используйте клиент через async with — так HTTP-сессия корректно закрывается. Даже если TikTok возвращает ошибку внутри ответа HTTP 200, SDK превращает её в исключение вроде AuthError, PermissionError или RateLimitError.
import asyncio
import os
import secrets
from socialift import TikTok
# SOCIALIFT_LICENSE_KEY тоже должен быть задан
tt = TikTok(
client_key=os.environ["TIKTOK_CLIENT_KEY"],
client_secret=os.environ["TIKTOK_CLIENT_SECRET"],
)
# То же самое: tt = TikTok.from_env()
async def main():
async with tt:
state = secrets.token_urlsafe(16) # сохраните и сверьте в callback
url = tt.login_url(redirect_uri="https://example.com/tiktok/callback", state=state)
print(url)
# в callback: bundle = await tt.exchange_code(code, redirect_uri=...)
# профиль: me = await tt.me(bundle.access_token)
asyncio.run(main())Вход и токены
OAuth через Login Kit: URL авторизации, обмен code, обновление и отзыв токена.
exchange_codefrom_envlogin_urlrefresh_tokenrevoke
exchange_code
asyncОбменивает code из callback Login Kit на TokenBundle с access и refresh токенами. Вызывается один раз в обработчике редиректа.
await tt.exchange_code(
code: str,
*,
redirect_uri: str,
code_verifier: Optional[str] = None,
) -> socialift.models.TokenBundle- Access token действует 24 часа, refresh token — 365 дней.
- Передайте тот же
redirect_uri, что и вlogin_url(); если поток начат с PKCE, добавьтеcode_verifier. - Запрос отправляется в form-urlencoded, как требует токен-эндпоинт TikTok; если в ответе нет
access_token, выбрасываетсяApiError.
from_env
classmethodСоздаёт клиент с ключами из переменных окружения TIKTOK_CLIENT_KEY и TIKTOK_CLIENT_SECRET. Дополнительные аргументы (scopes, business_id, timeout, license_key …) уходят в конструктор.
TikTok.from_env(**kwargs) -> TikTok- Отсутствующая переменная превращается в пустую строку и здесь не падает: ошибка
ConfigurationErrorпоявится, например, при вызовеlogin_url().
Формирует URL авторизации TikTok Login Kit, на который нужно перенаправить пользователя. Метод синхронный и не делает сетевых запросов.
tt.login_url(
*,
redirect_uri: str,
state: Optional[str] = None,
scopes: Optional[list[str]] = None,
code_challenge: Optional[str] = None,
code_challenge_method: Optional[str] = None,
disable_auto_auth: bool = False,
) -> strredirect_uriдолжен совпадать с одним из зарегистрированных в приложении: абсолютныйhttps, статический (без query и фрагмента), до 512 символов; в одном приложении — до 10 адресов.- Без
scopes=используются scope клиента (DEFAULT_SCOPES, если в конструктор не передали свои); TikTok ждёт их через запятую — SDK склеивает сам. - Для десктоп-приложений PKCE обязателен: TikTok ждёт
code_challengeкак SHA-256 от verifier в hex иcode_challenge_method="S256". SDK их не добавляет — передайте оба, а затемcode_verifierвexchange_code(). - При пустом
client_keyвыбрасываетсяConfigurationError.
url = tt.login_url(redirect_uri="https://siz.uz/cb", state=state)refresh_token
asyncПолучает новый access token по сохранённому refresh token. Запускайте по расписанию: access token живёт всего 24 часа.
await tt.refresh_token(refresh_token: str) -> socialift.models.TokenBundle- TikTok может вернуть
refresh_token, отличный от отправленного, — всегда сохраняйте новое значение из полученного bundle. - Refresh token действует 365 дней.
bundle = await tt.refresh_token(refresh_token)revoke
asyncОтзывает access token, и приложение теряет доступ к аккаунту пользователя. Используйте, когда пользователь нажимает «отключить».
await tt.revoke(token: str) -> bool- Возвращает
True, если TikTok принял запрос; удалите токены и в своей базе.
await tt.revoke(token)Профиль и видео
Профиль автора и его собственные видео (Open API v2).
iter_videos
asyncПроходит по страницам через videos() и собирает до max_items видео в один список. Удобно для синхронизации библиотеки автора с вашей базой.
await tt.iter_videos(
token: str,
*,
max_items: int = 100,
fields: Optional[str] = None,
) -> list[dict]max_items(по умолчанию 100) — предохранитель: у крупных аккаунтов тысячи видео, и бесконечный цикл упрётся в rate limit.- Каждая страница — отдельный запрос максимум на 20 видео.
Нужные разрешения:video.list
page = await tt.videos(token, limit=20)
all_videos = await tt.iter_videos(token, max_items=100)me
asyncВозвращает профиль автора как Profile: id (open_id), имя, аватар, био, число подписчиков, подписок и видео. Удобно сразу после входа, чтобы показать, кто подключился.
await tt.me(token: str, *, fields: Optional[str] = None) -> socialift.models.Profile- Scope по полям:
open_id, аватар иdisplay_name—user.info.basic;bio_description,profile_deep_link,is_verified—user.info.profile;follower_count,following_count,likes_count,video_count—user.info.stats. - По умолчанию запрашиваются все эти поля; чтобы получить только поля выданных scope, передайте в
fieldsболее короткую строку. - И
Profile.username, иfull_nameсодержатdisplay_name; исходный объект TikTok лежит вraw.
Нужные разрешения:user.info.basicuser.info.profileuser.info.stats
me = await tt.me(token)video
asyncПолучает данные видео по конкретным ID — например, чтобы обновить счётчики или истекающие ссылки на обложки уже известных видео.
await tt.video(
video_ids: Iterable[str],
token: str,
*,
fields: Optional[str] = None,
) -> list[dict]- TikTok принимает до 20 ID за запрос; SDK молча берёт только первые 20.
- Не рассчитывайте, что порядок результатов совпадёт с порядком ID, — сопоставляйте по
id. - Нужен scope
video.list.
Нужные разрешения:video.list
videos = await tt.video(["7300000000000000000"], token)videos
asyncВозвращает одну страницу собственных видео автора в виде {"data", "cursor", "has_more"}. Подходит для постраничного списка в интерфейсе.
await tt.videos(
token: str,
*,
limit: int = 20,
cursor: Optional[int] = None,
fields: Optional[str] = None,
) -> dict- TikTok отдаёт максимум 20 видео за запрос;
limitприводится к диапазону 1–20. cursor— UTC Unix-время в миллисекундах: для более старых видео передайтеcursorиз предыдущей страницы.- Нужен scope
video.list.
Нужные разрешения:video.list
page = await tt.videos(token, limit=20)
all_videos = await tt.iter_videos(token, max_items=100)Публикация
Content Posting API: прямая публикация, черновик во входящих, фото-пост и отслеживание статуса.
creator_infopublish_photospublish_statuspublish_videoupload_videowait_publish
creator_info
asyncВозвращает текущие настройки публикации автора: допустимые privacy_level_options, max_video_post_duration_sec, отключены ли комментарии, дуэты и stitch. Вызывайте перед каждым постом и стройте форму публикации по этому ответу.
await tt.creator_info(token: str) -> dict- Поток Direct Post в TikTok предполагает запрос creator info до инициализации поста.
- Отправляемый
privacy_levelдолжен быть одним изprivacy_level_options. - Поля с дневной квотой в ответе нет; когда автор упирается в дневной лимит постов через API, TikTok возвращает
spam_risk_too_many_posts, а SDK выбрасываетRateLimitError. - Нужен scope
video.publish.
Нужные разрешения:video.publish
info = await tt.creator_info(token)
print(info["privacy_level_options"])publish_photos
asyncСоздаёт фото-пост (карусель) из ссылок на изображения — публикует сразу или с draft=True отправляет черновиком во входящие автора.
await tt.publish_photos(
token: str,
*,
photo_urls: list[str],
title: Optional[str] = None,
description: Optional[str] = None,
privacy_level: str = 'SELF_ONLY',
cover_index: int = 0,
disable_comment: bool = False,
auto_add_music: bool = True,
draft: bool = False,
wait: bool = False,
brand_content: bool = False,
brand_organic: bool = False,
) -> dict- До 35 изображений, JPEG или WebP, до 20 МБ каждое; принимаются только ссылки (PULL_FROM_URL) с подтверждённого домена.
title— до 90,description— до 4000 символов UTF-16;cover_indexсчитается с нуля.- Для прямой публикации нужен scope
video.publish, дляdraft=True(MEDIA_UPLOAD) —video.upload.auto_add_musicработает только при прямой публикации. - Не используйте
wait=Trueвместе сdraft=True: статус остаётсяSEND_TO_USER_INBOX, пока автор не опубликует пост.
Нужные разрешения:video.publish
result = await tt.publish_photos(token, photo_urls=["https://cdn.siz.uz/1.jpg"], title="Karusel")publish_status
asyncВозвращает текущее состояние обработки поста по publish_id. Опрашивайте сами или используйте wait_publish().
await tt.publish_status(publish_id: str, token: str) -> dict- Значения
status:PROCESSING_UPLOAD(загрузка файла),PROCESSING_DOWNLOAD(скачивание по URL),SEND_TO_USER_INBOX(черновики),PUBLISH_COMPLETE,FAILED(причина вfail_reason). - Лимит — 30 запросов в минуту на access token.
publicaly_available_post_id(так пишет TikTok) приходит, только когда пост публичный и прошёл модерацию.
status = await tt.publish_status(publish_id, token)publish_video
asyncПубликует видео сразу в профиль автора (Direct Post) по публичной ссылке или из байтов/пути к файлу. Возвращает {"publish_id"}, а при wait=True — ещё и итоговый status.
await tt.publish_video(
token: str,
*,
video_url: Optional[str] = None,
video: Union[bytes, str, os.PathLike, NoneType] = None,
title: Optional[str] = None,
privacy_level: str = 'SELF_ONLY',
disable_comment: bool = False,
disable_duet: bool = False,
disable_stitch: bool = False,
cover_timestamp_ms: Optional[int] = None,
brand_content: bool = False,
brand_organic: bool = False,
chunk_size: Optional[int] = None,
wait: bool = False,
) -> dict- Пока приложение не прошло аудит TikTok, всё, что оно публикует, ограничено приватным просмотром, — поэтому
privacy_levelпо умолчаниюSELF_ONLY. - Для
video_url(PULL_FROM_URL) домен или префикс URL должен быть подтверждён, адрес —httpsбез редиректов, иначеurl_ownership_unverified(PermissionError). TikTok прекращает скачивание через час. - С
video=SDK загружает файл частями: до 5 МБ — одним куском, больше — частями по 5–64 МБ (chunk_size). - Запросы инициализации ограничены 6 в минуту на access token. Нужен scope
video.publish.
Нужные разрешения:video.publishvideo.upload
result = await tt.publish_video(token, video_url="https://cdn.siz.uz/reel.mp4", title="Salom TikTok!",
privacy_level="SELF_ONLY", wait=True)with open("reel.mp4", "rb") as f:
result = await tt.publish_video(token, video=f.read(), title="Salom!")upload_video
asyncОтправляет видео черновиком во входящие автора в TikTok, не публикуя его; автор редактирует и публикует сам в приложении. Используйте, когда подпись и приватность должен выбрать автор.
await tt.upload_video(
token: str,
*,
video_url: Optional[str] = None,
video: Union[bytes, str, os.PathLike, NoneType] = None,
chunk_size: Optional[int] = None,
wait: bool = False,
) -> dict- Нужен scope
video.upload; параметров подписи и приватности здесь нет. - TikTok допускает не больше 5 ожидающих отправок за любые 24 часа.
- Статус останавливается на
SEND_TO_USER_INBOXи становитсяPUBLISH_COMPLETEтолько после публикации автором.wait=Trueждёт именноPUBLISH_COMPLETE, поэтому завершитсяApiError, если автор не опубликует видео примерно за 2 минуты. - Правила источника те же, что у
publish_video(): дляvideo_urlнужен подтверждённый домен,video=загружается частями.
wait_publish
asyncОпрашивает publish_status(), пока пост не достигнет PUBLISH_COMPLETE, и возвращает этот статус. Именно его использует publish_video(wait=True).
await tt.wait_publish(
publish_id: str,
token: str,
*,
attempts: int = 40,
delay: float = 3.0,
) -> dict- По умолчанию 40 попыток × 3 секунды, около 2 минут; меняется через
attemptsиdelay. - При
FAILEDвыбрасываетсяApiErrorсfail_reason; когда попытки заканчиваются — тожеApiError. SEND_TO_USER_INBOXне считается завершением — не используйте метод для черновиков во входящих.
Бизнес-аккаунт и комментарии
TikTok API for Business: метрики аккаунта и модерация комментариев. Нужен business_id.
business_accountbusiness_videoscommentsdelete_commenthide_commentlike_commentpin_commentreply_comment
business_account
asyncВозвращает профиль бизнес-аккаунта и метрики по дням через TikTok API for Business. Для аналитики на уровне аккаунта.
await tt.business_account(
token: str,
*,
business_id: Optional[str] = None,
fields: Optional[list[str]] = None,
) -> dict- Запрос идёт на
business-api.tiktok.comс заголовкомAccess-Token— это отдельное семейство API, не Open API, который используетme(); приложению нужен доступ к TikTok API for Business. - Нужен
business_id(обычноopen_idавтора): передайте аргументом или задайтеbusiness_id=в клиенте, иначеConfigurationError. fields— список Python; SDK отправляет его строкой с JSON-массивом.
account = await tt.business_account(token)business_videos
asyncВозвращает видео бизнес-аккаунта с метриками по каждому через TikTok API for Business, постранично.
await tt.business_videos(
token: str,
*,
business_id: Optional[str] = None,
cursor: Optional[int] = None,
max_count: int = 20,
fields: Optional[list[str]] = None,
) -> dict- Для следующей страницы передайте
cursorиз предыдущего ответа;max_countпо умолчанию 20. - Нужны
business_id(аргумент или значение клиента) и доступ к TikTok API for Business.
stats = await tt.business_videos(token, max_count=20)delete_comment
asyncУдаляет комментарий через TikTok API for Business. Чтобы убрать комментарий из вида, не удаляя его, используйте hide_comment().
await tt.delete_comment(
comment_id: str,
token: str,
*,
business_id: Optional[str] = None,
) -> dict- Нужны
business_idи доступ к TikTok API for Business.
await tt.delete_comment(comment_id, token)hide_comment
asyncСкрывает комментарий под видео бизнес-аккаунта или снова показывает его при hidden=False — обратимый способ модерации.
await tt.hide_comment(
comment_id: str,
token: str,
*,
hidden: bool = True,
business_id: Optional[str] = None,
) -> dict- В
actionотправляетсяHIDEилиUNHIDE; нуженbusiness_id.
await tt.hide_comment(comment_id, token, hidden=True)like_comment
asyncСтавит лайк комментарию от имени бизнес-аккаунта или снимает его при liked=False.
await tt.like_comment(
comment_id: str,
token: str,
*,
liked: bool = True,
business_id: Optional[str] = None,
) -> dict- В
actionотправляетсяLIKEилиUNLIKE; нуженbusiness_id.
await tt.like_comment(comment_id, token, liked=True)pin_comment
asyncЗакрепляет комментарий вверху видео или открепляет его при pinned=False.
await tt.pin_comment(
comment_id: str,
token: str,
*,
pinned: bool = True,
business_id: Optional[str] = None,
) -> dict- Отправляет в
business/comment/top/actionTOPилиUNTOP; нуженbusiness_id.
await tt.pin_comment(comment_id, token, pinned=True)reply_comment
asyncПубликует ответ от имени бизнес-аккаунта на комментарий к его видео.
await tt.reply_comment(
comment_id: str,
token: str,
text: str,
*,
video_id: Optional[str] = None,
business_id: Optional[str] = None,
) -> dict- Порядок аргументов:
comment_id, token, text;video_idв SDK необязателен, но передавайте его, если он известен. - Нужны
business_idи доступ к TikTok API for Business.
await tt.reply_comment(comment_id, token, "Rahmat!", video_id=video_id)Низкоуровневые вызовы
Прямой доступ к эндпоинтам, для которых в SDK нет обёртки.
business
asyncВызывает любой эндпоинт TikTok API for Business с заголовком Access-Token. Для возможностей Business API, которые SDK не оборачивает.
await tt.business(
path: str,
token: str,
*,
method: str = 'POST',
json: Optional[dict] = None,
params: Optional[dict] = None,
) -> dictpathуказывается относительноhttps://business-api.tiktok.com/open_api/v1.3/; завершающий/добавляется автоматически.- Метод по умолчанию —
POST; ненулевойcodeв теле ответа превращается в исключение. business_idсам не добавляется — положите его вparamsилиjson.
data = await tt.business("business/get/", token, method="GET", params={"business_id": open_id})call
asyncВызывает любой эндпоинт Open API v2, для которого в SDK ещё нет обёртки, с заголовком Authorization: Bearer и проверкой ошибок TikTok. Возвращает сырой JSON.
await tt.call(
path: str,
token: str,
*,
method: str = 'POST',
json: Optional[dict] = None,
params: Optional[dict] = None,
) -> dictpathуказывается относительноhttps://open.tiktokapis.com/v2/; обязательный для TikTok завершающий/добавляется автоматически.- Метод по умолчанию —
POST; query-параметры вродеfieldsпередаются вparams, тело запроса — вjson. - Порядок аргументов —
path, token(вAds.callтокен идёт первым).
request
asyncСамый низкоуровневый HTTP-вызов: отправляет запрос на полный URL с повторами и выбрасывает ошибку, даже если TikTok вернул её внутри HTTP 200. Обычно удобнее call() или business(), которые сами добавляют заголовок авторизации.
await tt.request(method: str, url: str, **kwargs) -> Any- Заголовок авторизации не добавляется — передайте
headersсами. - Если
error.codeне"ok"(Open API) илиcodeне ноль (Business API), выбрасывается наследникApiError. - Повторы — по
RetryPolicy(ответы 429 и 5xx).
Общие методы всех клиентов
У каждого HTTP-клиента (Telegram, Facebook, Instagram, LinkedIn, TikTok, Ads) есть эти низкоуровневые методы: чтобы вызвать эндпоинт, для которого в SDK ещё нет обёртки, или читать данные постранично. По завершении блока async with соединение закрывается автоматически.
request
asyncОтправляет произвольный HTTP-запрос и возвращает JSON-ответ — для эндпоинта, у которого в SDK пока нет отдельного метода. Токен и параметры подписи (access_token, для Meta — appsecret_proof через socialift.crypto.appsecret_proof) вы передаёте сами в params или headers.
await tt.request(
method: str,
url: str,
*,
params: Optional[Mapping[str, Any]] = None,
data: Optional[Any] = None,
json: Optional[Any] = None,
headers: Optional[Mapping[str, str]] = None,
) -> Any- Значения
Noneвparamsне отправляются. - При лимите (
RateLimitError) и временных ошибках сервера (HTTP 429, 500, 502, 503, 504) запрос повторяется поRetryPolicy; если есть заголовокRetry-After, SDK ждёт указанное время. Обрыв сети выбрасывается какTransportError.
get
asyncКороткая форма request("GET", ...).
await tt.get(url: str, **kw) -> Anypost
asyncКороткая форма request("POST", ...).
await tt.post(url: str, **kw) -> Anydelete
asyncКороткая форма request("DELETE", ...).
await tt.delete(url: str, **kw) -> Anypaginate
asyncПроходит по курсорной пагинации Meta (paging.next) и возвращает все элементы data одним списком.
await tt.paginate(
url: str,
*,
params: Optional[Mapping[str, Any]] = None,
max_items: int = 500,
page_size: int = 100,
) -> list[dict]max_items(по умолчанию 500) — защитный предел: у крупного аккаунта могут быть десятки тысяч записей.page_size—limitодного запроса.
close
asyncЗакрывает HTTP-сессию, созданную самим SDK (переданную извне сессию не трогает). При использовании async with Client(...) вызывается автоматически.
await tt.close() -> NoneЧастые вопросы
Сколько живёт access token TikTok?
Access token действует 24 часа, refresh token — 365 дней. Обновляйте токен через refresh_token() минимум раз в сутки. TikTok может вернуть при обновлении другой refresh token — сохраняйте полученное значение и в следующий раз используйте именно его.
Почему видео, опубликованное в TikTok через API, видно только мне?
Весь контент, который публикует приложение без пройденного аудита TikTok, ограничивается приватным режимом просмотра. Поэтому в SDK privacy_level по умолчанию равен SELF_ONLY. После аудита выбирайте значение из списка privacy_level_options, который возвращает creator_info().
Можно ли загрузить видео в TikTok из файла, а не по URL?
Да: передайте байты или путь к файлу в publish_video(token, video=...). SDK использует FILE_UPLOAD и режет файлы больше 5 МБ на части по 5–64 МБ. Для video_url (PULL_FROM_URL) домен или префикс URL должен быть подтверждён в TikTok, адрес — https и без редиректов.
Чем publish_video отличается от upload_video?
publish_video публикует видео сразу в профиль (Direct Post, scope video.publish). upload_video отправляет видео черновиком во входящие автора в TikTok (scope video.upload): автор редактирует и публикует его сам в приложении. TikTok допускает не больше 5 ожидающих отправок за любые 24 часа.
Можно ли читать комментарии TikTok и отвечать на них через API?
Да, в SDK для этого есть comments, reply_comment, hide_comment и другие методы. Они работают через TikTok API for Business (business-api.tiktok.com) с заголовком Access-Token. Нужны business_id (обычно open_id автора) и доступ вашего приложения к этому API.
comments
asyncВозвращает комментарии к одному видео бизнес-аккаунта;
include_replies=Trueдобавляет ответы на комментарии первого уровня.dataиз ответа; следующая страница — черезcursor,max_countпо умолчанию 30.business_idи доступ к TikTok API for Business.