curl --request POST \
--url https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Idempotency-Key: <x-idempotency-key>' \
--data '
{
"source": {
"materialId": "<string>",
"youtubeUrl": "<string>",
"subtitleMaterialId": "<string>",
"targetSubtitleMaterialId": "<string>"
},
"language": {
"target": "zh-CN",
"source": "auto"
},
"options": {
"dubbingVersion": "V1",
"subtitle": {
"templateId": "<string>"
},
"voiceClone": {
"style": "emotional",
"mode": "role"
},
"transcribe": {
"mode": "fast",
"type": "default"
},
"translate": {
"mode": "default",
"prompt": "<string>"
},
"separation": {
"mode": "auto"
},
"dynamicVideoLength": {
"enable": true
},
"lipsync": {
"enable": false
},
"voiceSpeakers": {
"selectedVoicesList": [
{
"provider": "S1",
"voiceId": "<string>"
}
],
"speakerNum": "auto",
"timbreMethod": "clone"
}
},
"title": "<string>"
}
'import requests
url = "https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async"
payload = {
"source": {
"materialId": "<string>",
"youtubeUrl": "<string>",
"subtitleMaterialId": "<string>",
"targetSubtitleMaterialId": "<string>"
},
"language": {
"target": "zh-CN",
"source": "auto"
},
"options": {
"dubbingVersion": "V1",
"subtitle": { "templateId": "<string>" },
"voiceClone": {
"style": "emotional",
"mode": "role"
},
"transcribe": {
"mode": "fast",
"type": "default"
},
"translate": {
"mode": "default",
"prompt": "<string>"
},
"separation": { "mode": "auto" },
"dynamicVideoLength": { "enable": True },
"lipsync": { "enable": False },
"voiceSpeakers": {
"selectedVoicesList": [
{
"provider": "S1",
"voiceId": "<string>"
}
],
"speakerNum": "auto",
"timbreMethod": "clone"
}
},
"title": "<string>"
}
headers = {
"X-Idempotency-Key": "<x-idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Idempotency-Key': '<x-idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source: {
materialId: '<string>',
youtubeUrl: '<string>',
subtitleMaterialId: '<string>',
targetSubtitleMaterialId: '<string>'
},
language: {target: 'zh-CN', source: 'auto'},
options: {
dubbingVersion: 'V1',
subtitle: {templateId: '<string>'},
voiceClone: {style: 'emotional', mode: 'role'},
transcribe: {mode: 'fast', type: 'default'},
translate: {mode: 'default', prompt: '<string>'},
separation: {mode: 'auto'},
dynamicVideoLength: {enable: true},
lipsync: {enable: false},
voiceSpeakers: {
selectedVoicesList: [{provider: 'S1', voiceId: '<string>'}],
speakerNum: 'auto',
timbreMethod: 'clone'
}
},
title: '<string>'
})
};
fetch('https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'source' => [
'materialId' => '<string>',
'youtubeUrl' => '<string>',
'subtitleMaterialId' => '<string>',
'targetSubtitleMaterialId' => '<string>'
],
'language' => [
'target' => 'zh-CN',
'source' => 'auto'
],
'options' => [
'dubbingVersion' => 'V1',
'subtitle' => [
'templateId' => '<string>'
],
'voiceClone' => [
'style' => 'emotional',
'mode' => 'role'
],
'transcribe' => [
'mode' => 'fast',
'type' => 'default'
],
'translate' => [
'mode' => 'default',
'prompt' => '<string>'
],
'separation' => [
'mode' => 'auto'
],
'dynamicVideoLength' => [
'enable' => true
],
'lipsync' => [
'enable' => false
],
'voiceSpeakers' => [
'selectedVoicesList' => [
[
'provider' => 'S1',
'voiceId' => '<string>'
]
],
'speakerNum' => 'auto',
'timbreMethod' => 'clone'
]
],
'title' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Idempotency-Key: <x-idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async"
payload := strings.NewReader("{\n \"source\": {\n \"materialId\": \"<string>\",\n \"youtubeUrl\": \"<string>\",\n \"subtitleMaterialId\": \"<string>\",\n \"targetSubtitleMaterialId\": \"<string>\"\n },\n \"language\": {\n \"target\": \"zh-CN\",\n \"source\": \"auto\"\n },\n \"options\": {\n \"dubbingVersion\": \"V1\",\n \"subtitle\": {\n \"templateId\": \"<string>\"\n },\n \"voiceClone\": {\n \"style\": \"emotional\",\n \"mode\": \"role\"\n },\n \"transcribe\": {\n \"mode\": \"fast\",\n \"type\": \"default\"\n },\n \"translate\": {\n \"mode\": \"default\",\n \"prompt\": \"<string>\"\n },\n \"separation\": {\n \"mode\": \"auto\"\n },\n \"dynamicVideoLength\": {\n \"enable\": true\n },\n \"lipsync\": {\n \"enable\": false\n },\n \"voiceSpeakers\": {\n \"selectedVoicesList\": [\n {\n \"provider\": \"S1\",\n \"voiceId\": \"<string>\"\n }\n ],\n \"speakerNum\": \"auto\",\n \"timbreMethod\": \"clone\"\n }\n },\n \"title\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Idempotency-Key", "<x-idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async")
.header("X-Idempotency-Key", "<x-idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source\": {\n \"materialId\": \"<string>\",\n \"youtubeUrl\": \"<string>\",\n \"subtitleMaterialId\": \"<string>\",\n \"targetSubtitleMaterialId\": \"<string>\"\n },\n \"language\": {\n \"target\": \"zh-CN\",\n \"source\": \"auto\"\n },\n \"options\": {\n \"dubbingVersion\": \"V1\",\n \"subtitle\": {\n \"templateId\": \"<string>\"\n },\n \"voiceClone\": {\n \"style\": \"emotional\",\n \"mode\": \"role\"\n },\n \"transcribe\": {\n \"mode\": \"fast\",\n \"type\": \"default\"\n },\n \"translate\": {\n \"mode\": \"default\",\n \"prompt\": \"<string>\"\n },\n \"separation\": {\n \"mode\": \"auto\"\n },\n \"dynamicVideoLength\": {\n \"enable\": true\n },\n \"lipsync\": {\n \"enable\": false\n },\n \"voiceSpeakers\": {\n \"selectedVoicesList\": [\n {\n \"provider\": \"S1\",\n \"voiceId\": \"<string>\"\n }\n ],\n \"speakerNum\": \"auto\",\n \"timbreMethod\": \"clone\"\n }\n },\n \"title\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Idempotency-Key"] = '<x-idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": {\n \"materialId\": \"<string>\",\n \"youtubeUrl\": \"<string>\",\n \"subtitleMaterialId\": \"<string>\",\n \"targetSubtitleMaterialId\": \"<string>\"\n },\n \"language\": {\n \"target\": \"zh-CN\",\n \"source\": \"auto\"\n },\n \"options\": {\n \"dubbingVersion\": \"V1\",\n \"subtitle\": {\n \"templateId\": \"<string>\"\n },\n \"voiceClone\": {\n \"style\": \"emotional\",\n \"mode\": \"role\"\n },\n \"transcribe\": {\n \"mode\": \"fast\",\n \"type\": \"default\"\n },\n \"translate\": {\n \"mode\": \"default\",\n \"prompt\": \"<string>\"\n },\n \"separation\": {\n \"mode\": \"auto\"\n },\n \"dynamicVideoLength\": {\n \"enable\": true\n },\n \"lipsync\": {\n \"enable\": false\n },\n \"voiceSpeakers\": {\n \"selectedVoicesList\": [\n {\n \"provider\": \"S1\",\n \"voiceId\": \"<string>\"\n }\n ],\n \"speakerNum\": \"auto\",\n \"timbreMethod\": \"clone\"\n }\n },\n \"title\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"code": 200,
"message": "",
"data": {
"taskId": "<string>",
"taskType": "vt",
"status": "running",
"createdAt": "<string>",
"editorUrl": "<string>"
}
}Create translate and dub job
Create a translate-and-dub job on the same pipeline as vmeg.ai. The first pass renders the dubbed output: your webhook receives the first result (event openapi-app-media-translation), or poll Query job status until status is finished, then read result.outputs[0]. The job appears in My tasks on the website; open editorUrl to edit and re-export. Credits follow website pricing.
Differences from Standalone: options is optional; source takes materialId or youtubeUrl (no sourceUrl); taskType must match the material (vt video, at audio); title sets the job name on the website; output and extraData are rejected with 400; burned-in subtitles use options.subtitle instead of text; the webhook is sent only for the first result, not for re-exports on the website. Other unknown fields are ignored.
curl --request POST \
--url https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'X-Idempotency-Key: <x-idempotency-key>' \
--data '
{
"source": {
"materialId": "<string>",
"youtubeUrl": "<string>",
"subtitleMaterialId": "<string>",
"targetSubtitleMaterialId": "<string>"
},
"language": {
"target": "zh-CN",
"source": "auto"
},
"options": {
"dubbingVersion": "V1",
"subtitle": {
"templateId": "<string>"
},
"voiceClone": {
"style": "emotional",
"mode": "role"
},
"transcribe": {
"mode": "fast",
"type": "default"
},
"translate": {
"mode": "default",
"prompt": "<string>"
},
"separation": {
"mode": "auto"
},
"dynamicVideoLength": {
"enable": true
},
"lipsync": {
"enable": false
},
"voiceSpeakers": {
"selectedVoicesList": [
{
"provider": "S1",
"voiceId": "<string>"
}
],
"speakerNum": "auto",
"timbreMethod": "clone"
}
},
"title": "<string>"
}
'import requests
url = "https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async"
payload = {
"source": {
"materialId": "<string>",
"youtubeUrl": "<string>",
"subtitleMaterialId": "<string>",
"targetSubtitleMaterialId": "<string>"
},
"language": {
"target": "zh-CN",
"source": "auto"
},
"options": {
"dubbingVersion": "V1",
"subtitle": { "templateId": "<string>" },
"voiceClone": {
"style": "emotional",
"mode": "role"
},
"transcribe": {
"mode": "fast",
"type": "default"
},
"translate": {
"mode": "default",
"prompt": "<string>"
},
"separation": { "mode": "auto" },
"dynamicVideoLength": { "enable": True },
"lipsync": { "enable": False },
"voiceSpeakers": {
"selectedVoicesList": [
{
"provider": "S1",
"voiceId": "<string>"
}
],
"speakerNum": "auto",
"timbreMethod": "clone"
}
},
"title": "<string>"
}
headers = {
"X-Idempotency-Key": "<x-idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'X-Idempotency-Key': '<x-idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
source: {
materialId: '<string>',
youtubeUrl: '<string>',
subtitleMaterialId: '<string>',
targetSubtitleMaterialId: '<string>'
},
language: {target: 'zh-CN', source: 'auto'},
options: {
dubbingVersion: 'V1',
subtitle: {templateId: '<string>'},
voiceClone: {style: 'emotional', mode: 'role'},
transcribe: {mode: 'fast', type: 'default'},
translate: {mode: 'default', prompt: '<string>'},
separation: {mode: 'auto'},
dynamicVideoLength: {enable: true},
lipsync: {enable: false},
voiceSpeakers: {
selectedVoicesList: [{provider: 'S1', voiceId: '<string>'}],
speakerNum: 'auto',
timbreMethod: 'clone'
}
},
title: '<string>'
})
};
fetch('https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'source' => [
'materialId' => '<string>',
'youtubeUrl' => '<string>',
'subtitleMaterialId' => '<string>',
'targetSubtitleMaterialId' => '<string>'
],
'language' => [
'target' => 'zh-CN',
'source' => 'auto'
],
'options' => [
'dubbingVersion' => 'V1',
'subtitle' => [
'templateId' => '<string>'
],
'voiceClone' => [
'style' => 'emotional',
'mode' => 'role'
],
'transcribe' => [
'mode' => 'fast',
'type' => 'default'
],
'translate' => [
'mode' => 'default',
'prompt' => '<string>'
],
'separation' => [
'mode' => 'auto'
],
'dynamicVideoLength' => [
'enable' => true
],
'lipsync' => [
'enable' => false
],
'voiceSpeakers' => [
'selectedVoicesList' => [
[
'provider' => 'S1',
'voiceId' => '<string>'
]
],
'speakerNum' => 'auto',
'timbreMethod' => 'clone'
]
],
'title' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"X-Idempotency-Key: <x-idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async"
payload := strings.NewReader("{\n \"source\": {\n \"materialId\": \"<string>\",\n \"youtubeUrl\": \"<string>\",\n \"subtitleMaterialId\": \"<string>\",\n \"targetSubtitleMaterialId\": \"<string>\"\n },\n \"language\": {\n \"target\": \"zh-CN\",\n \"source\": \"auto\"\n },\n \"options\": {\n \"dubbingVersion\": \"V1\",\n \"subtitle\": {\n \"templateId\": \"<string>\"\n },\n \"voiceClone\": {\n \"style\": \"emotional\",\n \"mode\": \"role\"\n },\n \"transcribe\": {\n \"mode\": \"fast\",\n \"type\": \"default\"\n },\n \"translate\": {\n \"mode\": \"default\",\n \"prompt\": \"<string>\"\n },\n \"separation\": {\n \"mode\": \"auto\"\n },\n \"dynamicVideoLength\": {\n \"enable\": true\n },\n \"lipsync\": {\n \"enable\": false\n },\n \"voiceSpeakers\": {\n \"selectedVoicesList\": [\n {\n \"provider\": \"S1\",\n \"voiceId\": \"<string>\"\n }\n ],\n \"speakerNum\": \"auto\",\n \"timbreMethod\": \"clone\"\n }\n },\n \"title\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-Idempotency-Key", "<x-idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async")
.header("X-Idempotency-Key", "<x-idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"source\": {\n \"materialId\": \"<string>\",\n \"youtubeUrl\": \"<string>\",\n \"subtitleMaterialId\": \"<string>\",\n \"targetSubtitleMaterialId\": \"<string>\"\n },\n \"language\": {\n \"target\": \"zh-CN\",\n \"source\": \"auto\"\n },\n \"options\": {\n \"dubbingVersion\": \"V1\",\n \"subtitle\": {\n \"templateId\": \"<string>\"\n },\n \"voiceClone\": {\n \"style\": \"emotional\",\n \"mode\": \"role\"\n },\n \"transcribe\": {\n \"mode\": \"fast\",\n \"type\": \"default\"\n },\n \"translate\": {\n \"mode\": \"default\",\n \"prompt\": \"<string>\"\n },\n \"separation\": {\n \"mode\": \"auto\"\n },\n \"dynamicVideoLength\": {\n \"enable\": true\n },\n \"lipsync\": {\n \"enable\": false\n },\n \"voiceSpeakers\": {\n \"selectedVoicesList\": [\n {\n \"provider\": \"S1\",\n \"voiceId\": \"<string>\"\n }\n ],\n \"speakerNum\": \"auto\",\n \"timbreMethod\": \"clone\"\n }\n },\n \"title\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.vmeg.ai/openapi/v1/app/task/media-translation/create-async")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-Idempotency-Key"] = '<x-idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"source\": {\n \"materialId\": \"<string>\",\n \"youtubeUrl\": \"<string>\",\n \"subtitleMaterialId\": \"<string>\",\n \"targetSubtitleMaterialId\": \"<string>\"\n },\n \"language\": {\n \"target\": \"zh-CN\",\n \"source\": \"auto\"\n },\n \"options\": {\n \"dubbingVersion\": \"V1\",\n \"subtitle\": {\n \"templateId\": \"<string>\"\n },\n \"voiceClone\": {\n \"style\": \"emotional\",\n \"mode\": \"role\"\n },\n \"transcribe\": {\n \"mode\": \"fast\",\n \"type\": \"default\"\n },\n \"translate\": {\n \"mode\": \"default\",\n \"prompt\": \"<string>\"\n },\n \"separation\": {\n \"mode\": \"auto\"\n },\n \"dynamicVideoLength\": {\n \"enable\": true\n },\n \"lipsync\": {\n \"enable\": false\n },\n \"voiceSpeakers\": {\n \"selectedVoicesList\": [\n {\n \"provider\": \"S1\",\n \"voiceId\": \"<string>\"\n }\n ],\n \"speakerNum\": \"auto\",\n \"timbreMethod\": \"clone\"\n }\n },\n \"title\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"code": 200,
"message": "",
"data": {
"taskId": "<string>",
"taskType": "vt",
"status": "running",
"createdAt": "<string>",
"editorUrl": "<string>"
}
}Authorizations
Send your API Key in the Authorization header (Bearer <api_key>). See Authentication.
Headers
Required on mutating POST requests that create tasks or change persisted data (max 64 characters). See Idempotency.
64Body
vt video translation | at audio translation. Must match the material type, otherwise 400.
vt, at Exactly one of materialId or youtubeUrl
Show child attributes
Show child attributes
Source and target locales for localization
Show child attributes
Show child attributes
Pipeline options (all optional). Voice rules match the website: voiceClone.style picks automatic dubbing; voiceSpeakers.selectedVoicesList picks voices manually (sv_* system, cv_* your cloned voices) and cannot be combined with voiceClone. dubbingVersion: V2 cannot be combined with either. Leave voiceSpeakers.timbreMethod empty when you set voices; a conflicting value returns 400.
Show child attributes
Show child attributes
Job name shown in My tasks (max 255 characters). Defaults to the file name or the YouTube video title.
255Response
Task accepted. editorUrl opens the job in the website editor.

