Discussions

Ask a Question
Answered

Question Regarding 10 API Credits for Non-Subscribed API Accounts

Hello,

Answered

Keeping the avatar look the same in all videos

We have an app in which we create avatars & videos using Heygen

Answered

I want to switch from tariff 29 to 99. Can you tell me if I will be paying for two tariffs?

I want to switch from tariff 29 to 99. Can you tell me if I will be paying for two tariffs?

Answered

Video agent limit

Hey Heygen development team.

Answered

v2/video/generate status 200 still shows error on panel

curl --location 'https://api.heygen.com/v2/video/generate'
--header 'accept: application/json'
--header 'content-type: application/json'
--header 'x-api-key: abcd'
--data '{
"video_inputs": [
{
"character": {
"type": "avatar",
"avatar_id": "1ee71d11eb11400a996b5861e412aed0",
"avatar_style": "normal"
},
"voice": {
"type": "text",
"input_text": "Hello how are you?",
"voice_id": "5d2fe6fd8dad41949db24f4321b6926a",
"speed": 1.1
}
}
],
"dimension": {
"width": 1280,
"height": 1920
}
}'

Answered

Need exact Video Agent generate payload to lock avatar identity + use asset_id files[]

Hi HeyGen Engineering Team,

Answered

API/ELevenLabs

Hello,
I’m on the Creator Plan with a 1-member Workspace.
My API key is valid but HeyGen returns: “missing user-read to execute this operation.”
It appears my Workspace API key does not include the user:read scope.
Can you enable full API scope permissions for my Workspace so I can integrate with HeyGen?

Answered
Answered

DIFFICULTIES TO GET GENERATED VIDEOS URL BACK IN ORDER TO DISPLAY THEM ON MY WEB APP

'Annie_expressive4_public', 'teaching' => 'Annie_expressive4_public', 'project_management'=> 'Annie_expressive4_public', 'pharmacy' => 'Annie_expressive4_public', 'agro' => 'Annie_expressive4_public', ]; $VOICE_ID = '0b41c487c6da4f5ba5782bbe462958e8'; // === UTILS === function logMessage($msg) { $logFile = __DIR__ . '/logs/avatar_gen.log'; if (!is_dir(dirname($logFile))) mkdir(dirname($logFile), 0755, true); $timestamp = date('Y-m-d H:i:s'); error_log("[$timestamp] [AvatarGen] $msg\n", 3, $logFile); echo "[$timestamp] $msg\n"; } function heyGenRequest($method, $url, $payload = null) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 60); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Accept: application/json', 'X-Api-Key: ' . HEYGEN_API_KEY ]); if ($method === 'POST' && $payload) { curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); } $response = curl_exec($ch); $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); $error = curl_error($ch); curl_close($ch); if ($error) { throw new Exception("cURL error: $error"); } // 🔍 Debug temporaire if ($http_code !== 200) { logMessage("DEBUG HTTP $http_code - URL: $url"); logMessage("DEBUG Response: " . substr($response, 0, 200)); } return [$http_code, json_decode($response, true)]; } // === ÉTAPE 1 : Lancer la génération === function generateVideo($text, $user_group) { global $AVATAR_MAP, $VOICE_ID; $avatar_id = $AVATAR_MAP[$user_group] ?? $AVATAR_MAP['default']; $payload = [ "video_inputs" => [[ "character" => [ "type" => "avatar", "avatar_id" => $avatar_id, "scale" => 1 ], "voice" => [ "type" => "text", "input_text" => $text, "voice_id" => $VOICE_ID ], "background" => ["type" => "color", "value" => "#f8fafc"] ]], "dimension" => ["width" => 1920, "height" => 1080], "test" => false, "caption" => false ]; for ($attempt = 1; $attempt <= MAX_RETRIES; $attempt++) { try { [$code, $data] = heyGenRequest('POST', HEYGEN_API_URL, $payload); if ($code === 200 && !empty($data['data']['video_id'])) { return $data['data']['video_id']; } else { $msg = "HeyGen error (attempt $attempt): HTTP $code - " . ($data['message'] ?? json_encode($data)); logMessage($msg); if ($attempt < MAX_RETRIES) sleep(RETRY_DELAY_SEC); } } catch (Exception $e) { logMessage("Exception (attempt $attempt): " . $e->getMessage()); if ($attempt < MAX_RETRIES) sleep(RETRY_DELAY_SEC); } } throw new Exception("Échec après " . MAX_RETRIES . " tentatives."); } // === ÉTAPE 2 : Attendre la fin de la génération === function waitForVideoCompletion($video_id) { $elapsed = 0; $check_interval = 5; $max_checks = MAX_WAIT_SEC / $check_interval; logMessage("⏳ Attente de la complétion de la vidéo (max " . MAX_WAIT_SEC . " sec)..."); logMessage("🔍 Video ID: $video_id"); // Délai initial plus long (HeyGen met du temps à indexer) sleep(25); for ($check = 1; $check <= $max_checks; $check++) { try { // ✅ CORRECTION DÉFINITIVE : POST avec video_id dans le body JSON (API v1) $payload = ['video_id' => $video_id]; [$code, $data] = heyGenRequest('POST', HEYGEN_STATUS_URL, $payload); if ($code === 200 && !empty($data['data'])) { $status = $data['data']['status'] ?? 'unknown'; logMessage("CallCheck #$check (elapsed: {$elapsed}s) - Statut: $status"); if ($status === 'completed') { $video_url = $data['data']['video_url'] ?? null; if ($video_url) { logMessage("✅ URL CDN trouvée : $video_url"); return $video_url; } // Recherche alternative dans assets $assets = $data['data']['assets'] ?? []; foreach ($assets as $asset) { if (isset($asset['type']) && $asset['type'] === 'video' && isset($asset['url'])) { $video_url = $asset['url']; logMessage("✅ URL trouvée dans assets : $video_url"); return $video_url; } } throw new Exception("Vidéo complétée mais URL non trouvée"); } elseif ($status === 'failed') { $reason = $data['data']['reason'] ?? 'Unknown'; throw new Exception("Échec HeyGen : $reason"); } } else { $error_msg = $data['message'] ?? json_encode($data); logMessage("⚠️ CheckCall #$check - HTTP $code - $error_msg"); } sleep($check_interval); $elapsed += $check_interval; } catch (Exception $e) { logMessage("⚠️ CheckCall #$check erreur: " . $e->getMessage()); sleep($check_interval); $elapsed += $check_interval; } } throw new Exception("Timeout après " . MAX_WAIT_SEC . " secondes"); } // === ÉTAPE 3 : Mettre à jour la base === function updateMediaUrl($conn, $content_date, $user_group, $video_url) { logMessage("💾 Mise à jour de la base de données..."); $stmt = $conn->prepare(" UPDATE daily_content SET media_url = :url, media_type = 'video' WHERE content_date = :date AND user_group = :group "); $stmt->execute([ ':url' => $video_url, ':date' => $content_date, ':group' => $user_group ]); $rows = $stmt->rowCount(); logMessage("✅ Base mise à jour : $rows ligne(s) modifiée(s) - $user_group / $content_date → $video_url"); // Vérification $verify = $conn->prepare(" SELECT media_url, media_type FROM daily_content WHERE content_date = :date AND user_group = :group "); $verify->execute([':date' => $content_date, ':group' => $user_group]); $result = $verify->fetch(PDO::FETCH_ASSOC); if ($result && !empty($result['media_url'])) { logMessage("🔍 Vérification BDD : OK → " . substr($result['media_url'], 0, 60) . "..."); } else { logMessage("⚠️ Vérification BDD : ÉCHOUÉE"); } } // === SCRIPT PRINCIPAL === try { logMessage("╔════════════════════════════════════════════════════════════╗"); logMessage("║ DÉMARRAGE GÉNÉRATION VIDÉO HEYGEN v2 ║"); logMessage("╚════════════════════════════════════════════════════════════╝"); $stmt = $conn->prepare(" SELECT id, content_date, user_group, reading_text FROM daily_content WHERE content_date = :today AND (media_url IS NULL OR media_url = '' OR media_type != 'video') AND reading_text IS NOT NULL AND TRIM(reading_text) != '' "); $stmt->execute([':today' => date('Y-m-d')]); $contents = $stmt->fetchAll(PDO::FETCH_ASSOC); if (empty($contents)) { logMessage("ℹ️ Aucun contenu à traiter aujourd'hui."); exit(0); } logMessage("📋 " . count($contents) . " contenu(s) trouvé(s) à traiter"); foreach ($contents as $row) { $text = trim($row['reading_text']); $user_group = $row['user_group']; $content_date = $row['content_date']; $content_id = $row['id']; if (empty($text)) continue; logMessage("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"); logMessage("🎬 Traitement : $user_group / $content_date (ID: $content_id)"); logMessage("📝 Texte (premiers 50 caractères): " . substr($text, 0, 50) . "..."); try { $video_id = generateVideo($text, $user_group); logMessage("⏳ Job HeyGen lancé : $video_id"); logMessage("🌐 Suivre sur : https://app.heygen.com/videos/$video_id"); $video_url = waitForVideoCompletion($video_id); if (empty($video_url)) { throw new Exception("URL de vidéo vide"); } updateMediaUrl($conn, $content_date, $user_group, $video_url); logMessage("✅ VIDÉO GÉNÉRÉE ET STOCKÉE !"); logMessage("🎬 URL publique : $video_url"); } catch (Exception $e) { logMessage("❌ ÉCHEC pour $user_group : " . $e->getMessage()); } } logMessage("╔════════════════════════════════════════════════════════════╗"); logMessage("║ GÉNÉRATION TERMINÉE ║"); logMessage("╚════════════════════════════════════════════════════════════╝"); logMessage("💡 Rechargez enregistrement.php pour voir la vidéo !"); } catch (Exception $e) { logMessage("🔥 ERREUR CRITIQUE : " . $e->getMessage()); exit(1); } ?>
Answered