Upload videos to TikTok programmatically using DraftClip.
All API requests require authentication using an API key. Include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
/api/upload.php
Upload a video to the connected TikTok account.
| Parameter | Type | Required | Description |
|---|---|---|---|
video |
file | Yes | Video file (MP4, MOV, AVI). Max 500MB |
description |
string | Yes | Video caption/description (max 2200 characters) - This appears as the video caption on TikTok |
privacy_level |
string | No | SELF_ONLY, MUTUAL_FOLLOW_FRIENDS, PUBLIC_TO_EVERYONE (default: SELF_ONLY) |
curl -X POST https://drafttok.app/api/upload.php \
-H "Authorization: Bearer ttapi_YOUR_API_KEY_HERE" \
-F "video=@/path/to/video.mp4" \
-F "description=My Awesome Video - Check out this amazing content!" \
-F "privacy_level=SELF_ONLY"
import requests
url = "https://drafttok.app/api/upload.php"
headers = {
"Authorization": "Bearer ttapi_YOUR_API_KEY_HERE"
}
files = {
"video": open("/path/to/video.mp4", "rb")
}
data = {
"description": "My Awesome Video - Check out this amazing content!",
"privacy_level": "SELF_ONLY"
}
response = requests.post(url, headers=headers, files=files, data=data)
print(response.json())
const FormData = require('form-data');
const fs = require('fs');
const fetch = require('node-fetch');
const form = new FormData();
form.append('video', fs.createReadStream('/path/to/video.mp4'));
form.append('description', 'My Awesome Video - Check out this amazing content!');
form.append('privacy_level', 'SELF_ONLY');
fetch('https://drafttok.app/api/upload.php', {
method: 'POST',
headers: {
'Authorization': 'Bearer ttapi_YOUR_API_KEY_HERE'
},
body: form
})
.then(res => res.json())
.then(data => console.log(data));
{
"success": true,
"message": "Video uploaded successfully",
"data": {
"publish_id": "v0201fg0000cg...",
"description": "My Awesome Video - Check out this amazing content!",
"status": "PROCESSING_UPLOAD"
}
}
{
"error": "Error message description"
}
/api/video_status.php?publish_id=YOUR_PUBLISH_ID
Check the processing status of an uploaded video. Use the publish_id returned from the upload endpoint.
| Parameter | Type | Required | Description |
|---|---|---|---|
publish_id |
string | Yes | Publish ID from upload response |
curl -X GET "https://drafttok.app/api/video_status.php?publish_id=v0201fg0000cg..." \
-H "Authorization: Bearer ttapi_YOUR_API_KEY_HERE"
import requests
url = "https://drafttok.app/api/video_status.php"
headers = {
"Authorization": "Bearer ttapi_YOUR_API_KEY_HERE"
}
params = {
"publish_id": "v0201fg0000cg..."
}
response = requests.get(url, headers=headers, params=params)
print(response.json())
{
"success": true,
"data": {
"publish_id": "v0201fg0000cg...",
"status": "PUBLISH_COMPLETE",
"status_label": "Published",
"status_description": "Video has been successfully published",
"is_complete": true,
"publicaly_available_post_id": "7123456789012345678"
},
"message": "Video has been successfully published"
}
| Status | Description | Is Complete? |
|---|---|---|
PROCESSING_UPLOAD |
Video is being uploaded to TikTok servers | No |
PROCESSING |
Video is being processed by TikTok | No |
PUBLISH_COMPLETE |
Video has been successfully published | Yes |
FAILED |
Video upload/processing failed | Yes |
SEND_TO_USER_INBOX |
Video sent to inbox (draft mode) | Yes |
is_complete: true)| Code | Description |
|---|---|
| 400 | Bad Request - Missing or invalid parameters |
| 401 | Unauthorized - Invalid or missing API key |
| 405 | Method Not Allowed - Wrong HTTP method |
| 429 | Too Many Requests - Quota exceeded |
| 500 | Internal Server Error - Upload failed |
Please be respectful with API usage. Excessive requests may be rate-limited.
Here's a complete Python example showing how to upload a video and monitor its status:
import requests
import time
API_KEY = "ttapi_YOUR_API_KEY_HERE"
BASE_URL = "https://drafttok.app"
# Step 1: Upload video
print("Uploading video...")
upload_url = f"{BASE_URL}/api/upload.php"
headers = {"Authorization": f"Bearer {API_KEY}"}
files = {"video": open("video.mp4", "rb")}
data = {
"title": "My Video",
"description": "Test upload",
"privacy_level": "SELF_ONLY"
}
response = requests.post(upload_url, headers=headers, files=files, data=data)
result = response.json()
if not result.get("success"):
print(f"Upload failed: {result}")
exit(1)
publish_id = result["data"]["publish_id"]
print(f"Upload successful! Publish ID: {publish_id}")
# Step 2: Poll for status
print("Checking video status...")
status_url = f"{BASE_URL}/api/video_status.php"
max_attempts = 60 # Max 5 minutes (60 * 5 seconds)
attempt = 0
while attempt < max_attempts:
attempt += 1
# Check status
response = requests.get(
status_url,
headers=headers,
params={"publish_id": publish_id}
)
status_result = response.json()
if status_result.get("success"):
status = status_result["data"]["status"]
is_complete = status_result["data"]["is_complete"]
print(f"[{attempt}] Status: {status}")
if is_complete:
if status == "PUBLISH_COMPLETE":
post_id = status_result["data"].get("publicaly_available_post_id")
print(f"✓ Video published successfully! Post ID: {post_id}")
elif status == "FAILED":
reason = status_result["data"].get("fail_reason", "Unknown")
print(f"✗ Video processing failed: {reason}")
break
else:
print(f"Status check error: {status_result}")
# Wait before next check
time.sleep(5)
else:
print("Timeout: Video is still processing after 5 minutes")
print("Done!")
const FormData = require('form-data');
const fs = require('fs');
const fetch = require('node-fetch');
const API_KEY = 'ttapi_YOUR_API_KEY_HERE';
const BASE_URL = 'https://drafttok.app';
async function uploadAndMonitor() {
// Step 1: Upload video
console.log('Uploading video...');
const form = new FormData();
form.append('video', fs.createReadStream('video.mp4'));
form.append('title', 'My Video');
form.append('description', 'Test upload');
form.append('privacy_level', 'SELF_ONLY');
const uploadResponse = await fetch(`${BASE_URL}/api/upload.php`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}` },
body: form
});
const uploadResult = await uploadResponse.json();
if (!uploadResult.success) {
console.error('Upload failed:', uploadResult);
return;
}
const publishId = uploadResult.data.publish_id;
console.log(`Upload successful! Publish ID: ${publishId}`);
// Step 2: Poll for status
console.log('Checking video status...');
let attempts = 0;
const maxAttempts = 60;
while (attempts < maxAttempts) {
attempts++;
const statusResponse = await fetch(
`${BASE_URL}/api/video_status.php?publish_id=${publishId}`,
{ headers: { 'Authorization': `Bearer ${API_KEY}` } }
);
const statusResult = await statusResponse.json();
if (statusResult.success) {
const { status, is_complete } = statusResult.data;
console.log(`[${attempts}] Status: ${status}`);
if (is_complete) {
if (status === 'PUBLISH_COMPLETE') {
console.log('✓ Video published successfully!');
} else if (status === 'FAILED') {
console.log('✗ Video processing failed');
}
break;
}
}
// Wait 5 seconds before next check
await new Promise(resolve => setTimeout(resolve, 5000));
}
console.log('Done!');
}
uploadAndMonitor();
For questions or issues, check your dashboard for upload logs and status information.