n8n upload to TikTok with the HTTP Request node
n8n has no TikTok node in its docs. Upload with HTTP Request nodes: query creator info, init a Direct Post with FILE_UPLOAD, then PUT the bytes.

To upload to TikTok from n8n, use HTTP Request nodes against TikTok's Content Posting API: query the creator's info, initialize a Direct Post with FILE_UPLOAD, then PUT the video bytes to the upload_url TikTok returns. n8n's node docs list no TikTok node, and TikTok's PULL_FROM_URL only takes a URL on a domain or URL prefix you have verified, so the workflow downloads the file and pushes it.
TikTok's rules are quoted from its Direct Post reference and Media Transfer Guide, n8n's from its HTTP Request node docs, and the Sume facts from Runs and results, all read on 2026-09-28. Sume has no TikTok or n8n connector; every step is a plain HTTPS call.
Is there an n8n TikTok node?
Not among n8n's built-in nodes: its documentation index goes from TheHive 5 straight to TimescaleDB. n8n describes the HTTP Request node as the way to query data from any app or service with a REST API, so that is the TikTok node. Before the workflow can post, TikTok needs:
- A registered app with the Content Posting API product and its Direct Post configuration turned on.
- Approval for the
video.publishscope, and a TikTok user who has authorized your app for it. Their access token goes in an n8n generic credential (Header auth) asAuthorization: Bearer …. - An audit before anything goes public: all content posted by unaudited clients is restricted to private viewing mode.
Which nodes does the upload need?
Start from a workflow that already holds a finished Sume run, such as the one in n8n AI video workflow with a Wait node, whose last HTTP Request node reads GET /v1/format-runs/{run_id}. Name that node Read run, then add four HTTP Request nodes in this order, so the downloaded file sits on the item the upload node receives:
| Node | Request | Key settings |
|---|---|---|
| Creator info | POST https://open.tiktokapis.com/v2/post/publish/creator_info/query/ | Returns privacy_level_options and max_video_post_duration_sec |
| Init | POST https://open.tiktokapis.com/v2/post/publish/video/init/ | JSON body below; returns publish_id and upload_url |
| Download | GET the receipt's primary_output_url | Response Format: File, Put Output in Field: data. No Sume key needed: the URL is public |
| Upload | PUT the Init node's upload_url | Send Body: n8n Binary File, Input Data Field Name data; Content-Type, Content-Length, and Content-Range headers |
{
"post_info": {
"title": "Three tips for better sleep #sleep",
"privacy_level": "SELF_ONLY",
"brand_content_toggle": false,
"is_aigc": true
},
"source_info": {
"source": "FILE_UPLOAD",
"video_size": {{ $('Read run').item.json.data.artifacts[0].size_bytes }},
"chunk_size": {{ $('Read run').item.json.data.artifacts[0].size_bytes }},
"total_chunk_count": 1
}
}What goes in the init and upload requests?
n8n's $() expression returns a named node's data, and .item the item that produced the current one, which is how the Init body reads the receipt two nodes back.
video_sizeis the file's size in bytes. Sume lists every file on the receipt'sartifacts[]withurl,content_type, andsize_bytes; the code assumes the video is the first entry, so check that itsurlmatchesprimary_output_url.privacy_levelmust be one of theprivacy_level_optionsthe creator-info call returned;SELF_ONLYhere keeps test posts private.brand_content_toggleis marked required in TikTok's field table; set it totrueonly for a paid partnership that promotes a third-party business.is_aigc: truelabels the post as AI-generated content in its description.- One chunk works up to 64 MB: TikTok wants files under 5 MB sent whole, and files over 64 MB in multiple chunks of 5–64 MB, uploaded in order.
- On the Upload node,
Content-Rangeisbytes 0-{size minus 1}/{size}, andContent-Typeis the artifact'scontent_type; Sume's Timeline renders MP4 by default. Theupload_urlis valid for one hour.
What errors should the workflow expect?
TikTok answers with an error.code; anything other than ok means the request did not succeed. Codes worth handling in an automated workflow:
unaudited_client_can_only_post_to_private_accounts: an unaudited app can only post to a private account, and the init call is blocked.access_token_invalid(401): the user's access token is invalid or has expired, so update the n8n credential.url_ownership_unverified: you triedPULL_FROM_URLwith a URL outside your verified domains. Amedia.sume.comURL is on Sume's domain, which is why this build pushes the file (which URL TikTok can pull).spam_risk_too_many_posts: the user's daily post cap from the API is reached.rate_limit_exceeded(429): each user access token is limited to 6 init requests per minute, so space out a batch with the node's Batching option.- After the upload, check progress with TikTok's Get Post Status endpoint and the
publish_idfrom Init.
Sources
- n8n: HTTP Request node (read 2026-09-28)
- n8n: documentation index (llms.txt) (read 2026-09-28)
- n8n: NodeOutputData expression reference (read 2026-09-28)
- TikTok for Developers: Direct Post reference (read 2026-09-28)
- TikTok for Developers: Get Started, Direct Post (read 2026-09-28)
- TikTok for Developers: Media Transfer Guide (read 2026-09-28)
- Runs and results
- Timeline 1.0
Related posts
More in Integrations
- n8n: upload a file to Google Drive from a URL
Download the file with n8n's HTTP Request node set to return a File, then upload that binary with the Google Drive node's Upload operation into a folder.
- PowerShell Invoke-RestMethod POST JSON with a Bearer token
Convert a hashtable with ConvertTo-Json -Depth, then call Invoke-RestMethod -Method Post -ContentType 'application/json' with a Bearer header.
- Python requests retry: backoff, Retry-After, and POST
Requests doesn't retry by default. Mount urllib3's Retry on a Session with backoff and status_forcelist, and retry POST only with an Idempotency-Key.
- Rails webhooks: verify an HMAC signature in a controller
Read request.raw_post, skip CSRF for that action only, check OpenSSL::HMAC.hexdigest against each sume-v1 entry with secure_compare, then head 204.
Written by Sume