Skip to main content

tiktok

Upload videos to the user's TikTok drafts/inbox, where they finish posting in the TikTok app. Use when the user wants to publish or post a generated video to TikTok, or send a video to their TikTok drafts.

インストールへ移動

ソース情報

リポジトリ
AceDataCloud/Skills
ソースの最終更新活動
2026年8月6日 03:55
検出された SKILL.md の言語
英語
スター
17
フォーク
1

インストール方法

デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。

ソースファイルを確認

インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。

ファイルエクスプローラー
2 ファイル

SKILL.md を表示中

SKILL.md
ソースの指示 · 読み取り専用プレビュー
name
tiktok
description
Upload videos to the user's TikTok drafts/inbox, where they finish posting in the TikTok app. Use when the user wants to publish or post a generated video to TikTok, or send a video to their TikTok drafts.
when_to_use
Trigger when the user wants to push a video (e.g. one generated by the video skills) to TikTok. Upload drops it into their drafts and they finish posting in the app — this is the working path. Direct Post (publishing immediately with caption + privacy) requires an audit this app has not passed yet; do not use it.
connections
["tiktok"]
allowed_tools
["Bash"]
license
Apache-2.0
metadata
{"author":"acedatacloud","version":"2.2"}
Call the **TikTok API v2** with `curl + jq`. The user's OAuth bearer token is in `$TIKTOK_TOKEN`; every call needs `Authorization: Bearer $TIKTOK_TOKEN`. Base URL: `https://open.tiktokapis.com/v2`. ```bash T="https://open.tiktokapis.com/v2"; AUTH="Authorization: Bearer $TIKTOK_TOKEN" ``` Responses wrap everything in `{"data":…,"error":{"code","message","log_id"}}`. **Check `error.code`, not just the HTTP status** — several real failures (`spam_risk_too_many_posts`, `spam_risk_user_banned_from_posting`, `reached_active_user_cap`) come back as **HTTP 200** with a non-`ok` code. Show `error.message` verbatim. `401` / `access_token_invalid` = re-connect TikTok. ## Read the account ```bash # Basic profile — open_id identifies the user for every posting call curl -sS -H "$AUTH" "$T/user/info/?fields=open_id,display_name,avatar_url" \ | jq '.data.user' ``` Follower / like counts, bio, and the user's video list need the **Display API** scopes (`user.info.stats`, `user.info.profile`, `video.list`), which this app has not been granted — don't call `/v2/video/list/` or request those fields, they will fail with `scope_not_authorized`. ## Upload the video to the user's drafts This is the working path. The video lands in the creator's TikTok **inbox / drafts**; they open the TikTok app to add caption, sound and privacy, then post. Required order: 1. Download the exact video locally, but do not upload it yet. 2. Call `request_action_confirmation` with `kind: "generic"`, the real video preview, and a summary that says this uploads to drafts rather than publishing. 3. If cancelled, stop. If confirmed, run exactly one upload: `python3 skills/tiktok/scripts/tiktok.py upload video.mp4`. 4. Poll with `python3 skills/tiktok/scripts/tiktok.py status PUBLISH_ID` until terminal. Never call `upload` again while polling. Two source modes. **`FILE_UPLOAD` is the reliable one** — `PULL_FROM_URL` only works from a domain verified in the developer portal, and ours is not verified yet (it returns `url_ownership_unverified`). ### FILE_UPLOAD (default) Download the video locally first, then init with its exact byte size. Files under 64 MB go up as a single chunk. ```bash SIZE=$(stat -f%z video.mp4 2>/dev/null || stat -c%s video.mp4) INIT=$(curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \ -d "$(jq -n --argjson s "$SIZE" \ '{source_info:{source:"FILE_UPLOAD", video_size:$s, chunk_size:$s, total_chunk_count:1}}')" \ "$T/post/publish/inbox/video/init/") echo "$INIT" | jq '{publish_id:.data.publish_id, error:.error.code}' UPLOAD_URL=$(echo "$INIT" | jq -r '.data.upload_url') curl -sS -X PUT "$UPLOAD_URL" \ -H "Content-Type: video/mp4" \ -H "Content-Length: $SIZE" \ -H "Content-Range: bytes 0-$((SIZE-1))/$SIZE" \ --data-binary @video.mp4 -o /dev/null -w '%{http_code}\n' ``` The `PUT` returns **201** when the whole file landed (206 for intermediate chunks). `upload_url` expires in **1 hour**. ### PULL_FROM_URL (only from a verified domain) ```bash curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \ -d "$(jq -n --arg u "$VIDEO_URL" '{source_info:{source:"PULL_FROM_URL", video_url:$u}}')" \ "$T/post/publish/inbox/video/init/" | jq '{publish_id:.data.publish_id, error}' ``` Needs HTTPS and **no redirects** (any 3xx fails). Domain verification covers subdomains downward only. ## Poll status ```bash curl -sS -X POST -H "$AUTH" -H "Content-Type: application/json" \ -d "$(jq -n --arg id "$PUBLISH_ID" '{publish_id:$id}')" \ "$T/post/publish/status/fetch/" | jq '.data | {status, fail_reason}' ``` `PROCESSING_UPLOAD` / `PROCESSING_DOWNLOAD` → **`SEND_TO_USER_INBOX`** = done, the video is waiting in the creator's TikTok inbox. Tell them to open the TikTok app to finish posting, and that processing takes a few minutes. Don't retry on `auth_removed`, `spam_risk_text`, `spam_risk`, or `spam_risk_user_banned_from_posting` — those are terminal. `internal` is retryable. ## Direct Post — NOT available yet Direct Post (`/v2/post/publish/video/init/`) publishes straight to the profile with a caption and privacy level. **Do not call it.** It needs a Content Posting API audit this app has not passed, so every attempt fails: ``` 403 unaudited_client_can_only_post_to_private_accounts ``` The `video.publish` scope is granted and `creator_info/query` works, which makes it look available — it is not. Until the audit clears, use the drafts path above. ## Gotchas - **Never hardcode `privacy_level`** if Direct Post is ever enabled. TikTok rejects values outside `privacy_level_options` and treats a defaulted privacy setting as a guideline violation for the whole app. - Rate limits per user token: `creator_info/query` 20/min, `video/init/` **6/min**, `status/fetch/` 30/min. TikTok also caps posts at roughly 15/day per creator, **shared across all apps** — another app can exhaust it. - `SEND_TO_USER_INBOX` is success for this flow, not an intermediate state. Don't wait for `PUBLISH_COMPLETE` — that only happens once the user posts from the app.
GitHubで見る