when publish samll videos 3mb 2mb it workes fine as long as it not chunked meaning less than 5MB and it is totalchunks var equal 1 as you can see in code below but when go to lager videos when you must chunk like 28mb it show me this error : The total chunk count is invalid
{
"success": false,
"error": "Failed to upload video: Client error: `POST /` resulted in a `400 Bad Request` response:\n{\"error\":{\"code\":\"invalid_params\",\"message\":\"The total chunk count is invalid\",\"log_id\":\"20250121074544981EFF65ABBF7906D (truncated...)\n",
"publish_id": null,
"video_size": 24700139,
"chunks": 5,
"chunksize": 5242880
}
this how u calculate the chunksize of a video i stored in public/videos
// Get video from public folder
$videoPath = public_path('videos/xyz.mp4');
if (!file_exists($videoPath)) {
return response()->json([
'success' => false,
'error' => 'Video file not found in public/videos folder'
], 404);
}
// Calculate video parameters with TikTok specs
$videoSize = (int)filesize($videoPath);
$minChunkSize = 5 * 1024 * 1024; // 5MB minimum
$maxChunkSize = 64 * 1024 * 1024; // 64MB maximum
// Handle small videos (<5MB)
if ($videoSize < $minChunkSize) {
$chunkSize = $videoSize;
$totalChunks = 1;
} else {
// Calculate optimal chunk size
$chunkSize = min($maxChunkSize, (int)ceil($videoSize / 1000));
$chunkSize = max($minChunkSize, $chunkSize);
$totalChunks = (int)ceil($videoSize / $chunkSize);
}
and here where i init video upload to tiktok
try {
$client = new Client(['timeout' => 300]);
// Initialize video upload
$initResponse = $client->post('/', [
'headers' => [
'Authorization' => 'Bearer ' . $usertiktok->access_token,
'Content-Type' => 'application/json'
],
'json' => [
'source_info' => [
'source' => 'FILE_UPLOAD',
'video_size' => $videoSize,
'chunk_size' => $chunkSize,
'total_chunk_count' => $totalChunks
],
'post_info' => [
'title' => $request->title,
'description' => $request->description ?? '',
'privacy_level' => $request->privacy_level,
'disable_duet' => false,
'disable_comment' => false,
'disable_stitch' => false
]
]
]);
and that is full code
public function uploadVideo(Request $request)
{
$account_id = auth()->user()->account_id;
$user_id = $request->user_id;
// Get video from public folder
$videoPath = public_path('videos/xyz.mp4');
if (!file_exists($videoPath)) {
return response()->json([
'success' => false,
'error' => 'Video file not found in public/videos folder'
], 404);
}
// Calculate video parameters with TikTok specs
$videoSize = (int)filesize($videoPath);
$minChunkSize = 5 * 1024 * 1024; // 5MB minimum
$maxChunkSize = 64 * 1024 * 1024; // 64MB maximum
// Handle small videos (<5MB)
if ($videoSize < $minChunkSize) {
$chunkSize = $videoSize;
$totalChunks = 1;
} else {
// Calculate optimal chunk size
$chunkSize = min($maxChunkSize, (int)ceil($videoSize / 1000));
$chunkSize = max($minChunkSize, $chunkSize);
$totalChunks = (int)ceil($videoSize / $chunkSize);
}
// Validate video size
if ($videoSize > 4 * 1024 * 1024 * 1024) { // 4GB max
return response()->json([
'success' => false,
'error' => 'Video size must be less than 4GB'
], 400);
}
// Validate chunk count
if ($totalChunks > 1000) {
return response()->json([
'success' => false,
'error' => 'Invalid chunk count. Must be maximum 1000'
], 400);
}
// Validate request
$request->validate([
'title' => 'required|string|max:150',
'description' => 'nullable|string|max:2200',
'privacy_level' => 'required|in:PUBLIC_TO_EVERYONE,MUTUAL_FOLLOW_FRIENDS,SELF_ONLY',
]);
$usertiktok = User::where("id", $user_id)
->where("account_id", $account_id)
->where("social_type", "tiktok")
->first();
if (!$usertiktok) {
return response()->json(["message" => "TikTok account not found"], 400);
}
try {
$client = new Client(['timeout' => 300]);
// Initialize video upload
$initResponse = $client->post('/', [
'headers' => [
'Authorization' => 'Bearer ' . $usertiktok->access_token,
'Content-Type' => 'application/json'
],
'json' => [
'source_info' => [
'source' => 'FILE_UPLOAD',
'video_size' => $videoSize,
'chunk_size' => $chunkSize,
'total_chunk_count' => $totalChunks
],
'post_info' => [
'title' => $request->title,
'description' => $request->description ?? '',
'privacy_level' => $request->privacy_level,
'disable_duet' => false,
'disable_comment' => false,
'disable_stitch' => false
]
]
]);
$initData = json_decode($initResponse->getBody(), true);
if (!isset($initData['data']['upload_url'])) {
throw new \Exception('Failed to get upload URL: ' . json_encode($initData));
}
$uploadUrl = $initData['data']['upload_url'];
$publishId = $initData['data']['publish_id'];
// Upload video chunks
$videoFile = null;
try {
$videoFile = fopen($videoPath, 'r');
if (!$videoFile) {
throw new \Exception('Failed to open video file');
}
for ($chunk = 0; $chunk < $totalChunks; $chunk++) {
$offset = $chunk * $chunkSize;
$currentChunkSize = ($chunk == $totalChunks - 1)
? ($videoSize - $offset)
: $chunkSize;
fseek($videoFile, $offset);
$chunkData = fread($videoFile, $currentChunkSize);
$response = $client->put($uploadUrl, [
'headers' => [
'Authorization' => 'Bearer ' . $usertiktok->access_token,
'Content-Type' => 'video/mp4',
'Content-Length' => $currentChunkSize,
'Content-Range' => sprintf('bytes %d-%d/%d',
$offset,
$offset + $currentChunkSize - 1,
$videoSize
)
],
'body' => $chunkData
]);
// Check response codes (206 for partial, 201 for complete)
$statusCode = $response->getStatusCode();
if ($statusCode !== ($chunk == $totalChunks - 1 ? 201 : 206)) {
throw new \Exception("Unexpected response code: $statusCode");
}
}
} finally {
if (is_resource($videoFile)) {
fclose($videoFile);
}
}
// Check upload status
$maxAttempts = 30;
$attempts = 0;
$status = 'PROCESSING';
while ($status === 'PROCESSING' && $attempts < $maxAttempts) {
$statusResponse = $client->post('/', [
'headers' => [
'Authorization' => 'Bearer ' . $usertiktok->access_token,
'Content-Type' => 'application/json'
],
'json' => [
'publish_id' => $publishId
]
]);
$statusData = json_decode($statusResponse->getBody(), true);
$status = $statusData['data']['status'] ?? 'PROCESSING';
if ($status === 'PROCESSING') {
sleep(2);
$attempts++;
}
}
if ($status === 'FAILED') {
throw new \Exception('Upload failed during processing');
}
return response()->json([
'success' => true,
'message' => 'Video uploaded successfully',
'data' => [
'publish_id' => $publishId,
'status' => $status,
'video_size' => $videoSize,
'chunks' => $totalChunks
]
]);
} catch (\Exception $e) {
Log::error('TikTok Upload Error', [
'error' => $e->getMessage(),
'user_id' => $user_id,
'video_size' => $videoSize ?? 0,
'chunks' => $totalChunks ?? 0,
'publish_id' => $publishId ?? null
]);
return response()->json([
'success' => false,
'error' => 'Failed to upload video: ' . $e->getMessage(),
'publish_id' => $publishId ?? null
], 500);
}
}
i tried to change the $totalChunks variable to be static as 1 but it give me different error
{
"success": false,
"error": "Failed to upload video: Client error: `POST /` resulted in a `400 Bad Request` response:\n{\"error\":{\"code\":\"invalid_params\",\"message\":\"The chunk size is invalid\",\"log_id\":\"20250120150836CF3EDDD9FB5BFC1C0A85\"}}\n",
"publish_id": null
}
and i also tried to send the video as one chunk like small video but it give differenet error which is error during processing video .
I followed everythinge according to this documentation and still not working , pls anyone with experience with publishing with tiktok api can help? Link to tiktok docs: