Wan 2.7 Video Editing
curl --request POST \
--url https://api.gravitex.ai/v1/video/generations \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"metadata.input.prompt": "<string>",
"metadata.input.media": [
{}
],
"metadata.input.media[].type": "<string>",
"metadata.input.media[].url": "<string>",
"metadata.parameters.resolution": "<string>",
"metadata.parameters.prompt_extend": true,
"metadata.parameters.watermark": true
}
'import requests
url = "https://api.gravitex.ai/v1/video/generations"
payload = {
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"metadata.input.prompt": "<string>",
"metadata.input.media": [{}],
"metadata.input.media[].type": "<string>",
"metadata.input.media[].url": "<string>",
"metadata.parameters.resolution": "<string>",
"metadata.parameters.prompt_extend": True,
"metadata.parameters.watermark": True
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
model: '<string>',
prompt: '<string>',
duration: 123,
'metadata.input.prompt': '<string>',
'metadata.input.media': [{}],
'metadata.input.media[].type': '<string>',
'metadata.input.media[].url': '<string>',
'metadata.parameters.resolution': '<string>',
'metadata.parameters.prompt_extend': true,
'metadata.parameters.watermark': true
})
};
fetch('https://api.gravitex.ai/v1/video/generations', 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.gravitex.ai/v1/video/generations",
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([
'model' => '<string>',
'prompt' => '<string>',
'duration' => 123,
'metadata.input.prompt' => '<string>',
'metadata.input.media' => [
[
]
],
'metadata.input.media[].type' => '<string>',
'metadata.input.media[].url' => '<string>',
'metadata.parameters.resolution' => '<string>',
'metadata.parameters.prompt_extend' => true,
'metadata.parameters.watermark' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.gravitex.ai/v1/video/generations"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"metadata.input.prompt\": \"<string>\",\n \"metadata.input.media\": [\n {}\n ],\n \"metadata.input.media[].type\": \"<string>\",\n \"metadata.input.media[].url\": \"<string>\",\n \"metadata.parameters.resolution\": \"<string>\",\n \"metadata.parameters.prompt_extend\": true,\n \"metadata.parameters.watermark\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.gravitex.ai/v1/video/generations")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"metadata.input.prompt\": \"<string>\",\n \"metadata.input.media\": [\n {}\n ],\n \"metadata.input.media[].type\": \"<string>\",\n \"metadata.input.media[].url\": \"<string>\",\n \"metadata.parameters.resolution\": \"<string>\",\n \"metadata.parameters.prompt_extend\": true,\n \"metadata.parameters.watermark\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gravitex.ai/v1/video/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"metadata.input.prompt\": \"<string>\",\n \"metadata.input.media\": [\n {}\n ],\n \"metadata.input.media[].type\": \"<string>\",\n \"metadata.input.media[].url\": \"<string>\",\n \"metadata.parameters.resolution\": \"<string>\",\n \"metadata.parameters.prompt_extend\": true,\n \"metadata.parameters.watermark\": true\n}"
response = http.request(request)
puts response.read_bodyWan
Wan 2.7 Video Editing
Alibaba Wan wan2.7-videoedit instruction-based video editing
POST
/
v1
/
video
/
generations
Wan 2.7 Video Editing
curl --request POST \
--url https://api.gravitex.ai/v1/video/generations \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"metadata.input.prompt": "<string>",
"metadata.input.media": [
{}
],
"metadata.input.media[].type": "<string>",
"metadata.input.media[].url": "<string>",
"metadata.parameters.resolution": "<string>",
"metadata.parameters.prompt_extend": true,
"metadata.parameters.watermark": true
}
'import requests
url = "https://api.gravitex.ai/v1/video/generations"
payload = {
"model": "<string>",
"prompt": "<string>",
"duration": 123,
"metadata.input.prompt": "<string>",
"metadata.input.media": [{}],
"metadata.input.media[].type": "<string>",
"metadata.input.media[].url": "<string>",
"metadata.parameters.resolution": "<string>",
"metadata.parameters.prompt_extend": True,
"metadata.parameters.watermark": True
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
model: '<string>',
prompt: '<string>',
duration: 123,
'metadata.input.prompt': '<string>',
'metadata.input.media': [{}],
'metadata.input.media[].type': '<string>',
'metadata.input.media[].url': '<string>',
'metadata.parameters.resolution': '<string>',
'metadata.parameters.prompt_extend': true,
'metadata.parameters.watermark': true
})
};
fetch('https://api.gravitex.ai/v1/video/generations', 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.gravitex.ai/v1/video/generations",
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([
'model' => '<string>',
'prompt' => '<string>',
'duration' => 123,
'metadata.input.prompt' => '<string>',
'metadata.input.media' => [
[
]
],
'metadata.input.media[].type' => '<string>',
'metadata.input.media[].url' => '<string>',
'metadata.parameters.resolution' => '<string>',
'metadata.parameters.prompt_extend' => true,
'metadata.parameters.watermark' => true
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.gravitex.ai/v1/video/generations"
payload := strings.NewReader("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"metadata.input.prompt\": \"<string>\",\n \"metadata.input.media\": [\n {}\n ],\n \"metadata.input.media[].type\": \"<string>\",\n \"metadata.input.media[].url\": \"<string>\",\n \"metadata.parameters.resolution\": \"<string>\",\n \"metadata.parameters.prompt_extend\": true,\n \"metadata.parameters.watermark\": true\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.gravitex.ai/v1/video/generations")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"metadata.input.prompt\": \"<string>\",\n \"metadata.input.media\": [\n {}\n ],\n \"metadata.input.media[].type\": \"<string>\",\n \"metadata.input.media[].url\": \"<string>\",\n \"metadata.parameters.resolution\": \"<string>\",\n \"metadata.parameters.prompt_extend\": true,\n \"metadata.parameters.watermark\": true\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gravitex.ai/v1/video/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"model\": \"<string>\",\n \"prompt\": \"<string>\",\n \"duration\": 123,\n \"metadata.input.prompt\": \"<string>\",\n \"metadata.input.media\": [\n {}\n ],\n \"metadata.input.media[].type\": \"<string>\",\n \"metadata.input.media[].url\": \"<string>\",\n \"metadata.parameters.resolution\": \"<string>\",\n \"metadata.parameters.prompt_extend\": true,\n \"metadata.parameters.watermark\": true\n}"
response = http.request(request)
puts response.read_bodyIntroduction
Call Alibaba Cloud Bailianwan2.7-videoedit through the Gravitex gateway to perform instruction-based editing on existing video (replace subjects, change clothing, adjust scene style, etc.). The API is async: submit a task first, then poll for results.
| Endpoint | Method | Path |
|---|---|---|
| Create video editing task | POST | /v1/video/generations |
| Query task status | GET | /v1/video/generations/{task_id} |
{task_id} is the id returned when the task is created.
Shares the unified video entry with Wan 2.7 Video Generation (T2V / I2V / R2V), but the model and
media parameter semantics differ—do not mix them.Authentication
string
required
Bearer Token, e.g.
Bearer sk-xxxxxxxxstring
required
Must be
application/jsonstring
Request trace ID; generate a unique value per request
Request parameters
string
required
Must be
wan2.7-videoeditstring
required
Video editing instruction
integer
Output video duration in seconds; example uses
4string
required
Raw prompt passed to Alibaba Cloud; recommend keeping it in sync with top-level
promptarray
required
Input media array; must include at least one video
string
required
Use
video for source video; reference_image for reference images (up to 4)string
required
Public HTTP/HTTPS URL or temporary URL meeting upstream requirements
string
720P or 1080Pboolean
Enable intelligent prompt rewriting
boolean
Add watermark
Request examples
Minimal request (video only):curl --location 'https://api.gravitex.ai/v1/video/generations' \
--header 'Authorization: Bearer sk-xxxxxxxx' \
--header 'Content-Type: application/json' \
--header 'X-Trace-ID: wan27-videoedit-test-001' \
--data '{
"model": "wan2.7-videoedit",
"prompt": "背景不变,把视频中的小羊换成黑色的",
"duration": 4,
"metadata": {
"input": {
"prompt": "背景不变,把视频中的小羊换成黑色的",
"media": [
{
"type": "video",
"url": "https://your-public-oss.example.com/input.mp4"
}
]
},
"parameters": {
"resolution": "720P",
"prompt_extend": true,
"watermark": false
}
}
}'
media array; use “图 1” in the prompt to refer to them. Up to 4 reference images are supported.
{
"model": "wan2.7-videoedit",
"prompt": "保持视频中的人物动作不变,把人物衣服替换成参考图中的黑色西装",
"duration": 4,
"metadata": {
"input": {
"prompt": "保持视频中的人物动作不变,把人物衣服替换成参考图中的黑色西装",
"media": [
{
"type": "video",
"url": "https://your-public-oss.example.com/input.mp4"
},
{
"type": "reference_image",
"url": "https://your-public-oss.example.com/reference.png"
}
]
},
"parameters": {
"resolution": "720P",
"prompt_extend": true,
"watermark": false
}
}
}
Create task response
On success, returns a standardized video task object (no outercode/message/data wrapper):
{
"id": "76dc2556-f4****************29247",
"object": "video",
"model": "wan2.7-videoedit",
"status": "queued",
"progress": 0,
"created_at": 1784714517,
"metadata": {
"output": {
"task_id": "76dc2556-f4****************29247",
"task_status": "PENDING"
},
"request_id": "86c168af-****************bf96d"
}
}
id for subsequent queries.
Query task
curl --location \
'https://api.gravitex.ai/v1/video/generations/76dc2556-f4****************29247' \
--header 'Authorization: Bearer sk-xxxxxxxx' \
--header 'X-Trace-ID: wan27-videoedit-query-001'
code/message/data wrapper:
{
"code": "success",
"message": "",
"data": {
"id": "76dc2556-f4****************29247",
"object": "video",
"model": "wan2.7-videoedit",
"status": "completed",
"progress": 100,
"created_at": 1784714517,
"completed_at": 1784714687,
"seconds": "8",
"url": "https://signed-result-url.example.com/result.mp4",
"video_url": "https://signed-result-url.example.com/result.mp4",
"metadata": {
"output": {
"task_status": "SUCCEEDED",
"input_video_duration": 4,
"output_video_duration": 4,
"video_url": "https://signed-result-url.example.com/result.mp4"
}
}
}
}
Status handling
Clients should usedata.status as the platform standard status:
data.status | Description | Client action |
|---|---|---|
queued | Queued | Continue polling |
in_progress | Generating | Continue polling |
completed | Success | Read data.video_url or data.url |
failed | Failed | Read data.error.message |
data.metadata.output.task_status (e.g. PENDING, SUCCEEDED); use for troubleshooting only, not as the primary status source.
Recommended poll interval: 5–15 seconds; avoid high-frequency polling.
Output video URL
On success, readdata.video_url first; data.url is also available (typically the same in the current adapter).
Output URLs are signed temporary addresses—do not store them permanently as business resource URLs. Download or copy to your own OSS within the validity period for long-term storage.
Duration and billing
In testing withduration: 4, upstream usage may look like:
| Field | Meaning |
|---|---|
input_video_duration | Input video duration |
output_video_duration | Output video duration |
usage.duration | Total billed duration (input + output) |
data.seconds | Gateway response total upstream duration (example: 8) |
data.seconds = 8 does not mean the output is 8 seconds—it is the combined input + output billing duration.
Alibaba Cloud official billing: charged by “input video duration + output video duration”; input images are not billed. See official billing documentation.
Common error troubleshooting
| Issue | Description |
|---|---|
media missing video | Must include at least { "type": "video", "url": "..." } |
| Video URL inaccessible | Do not use login-required pages, insufficient-permission, or expired OSS URLs; must be publicly accessible |
| Invalid JSON | Use true/false for booleans, not **true** etc. |
Only passed video_url | New integrations should use input.media; the gateway accepts legacy video_url but it is not recommended |
| Mixed with Wan 2.1 parameters | wan2.7-videoedit uses input.media; legacy wan2.1-vace-plus uses input.function = video_repainting + input.video_url—do not mix |
Minimal Python example
import time
import uuid
import requests
BASE_URL = "https://api.gravitex.ai"
API_KEY = "sk-xxxxxxxx"
headers = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"X-Trace-ID": uuid.uuid4().hex,
}
payload = {
"model": "wan2.7-videoedit",
"prompt": "背景不变,把视频中的小羊换成黑色的",
"duration": 4,
"metadata": {
"input": {
"prompt": "背景不变,把视频中的小羊换成黑色的",
"media": [
{
"type": "video",
"url": "https://your-public-oss.example.com/input.mp4",
}
],
},
"parameters": {
"resolution": "720P",
"prompt_extend": True,
"watermark": False,
},
},
}
response = requests.post(
f"{BASE_URL}/v1/video/generations",
headers=headers,
json=payload,
timeout=30,
)
response.raise_for_status()
task = response.json()
task_id = task["id"]
while True:
result = requests.get(
f"{BASE_URL}/v1/video/generations/{task_id}",
headers={
"Authorization": f"Bearer {API_KEY}",
"X-Trace-ID": uuid.uuid4().hex,
},
timeout=30,
)
result.raise_for_status()
data = result.json()["data"]
status = data["status"]
print(status, data.get("progress", 0))
if status == "completed":
print("video_url:", data.get("video_url") or data.get("url"))
break
if status == "failed":
raise RuntimeError(data.get("error", {}).get("message", "video generation failed"))
time.sleep(10)
