- Automatically routed based on parameters: Text-to-Video / Image-to-Video (first frame, first-last frame, video continuation)
- Supports 720P/1080P resolution, 2-15 seconds duration
- Supports custom audio (background music in text-to-video mode, driving audio in image-to-video mode)
Request example
curl --request POST \
--url https://api.openveer.com/v1/videos/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"model": "wan2.7",
"prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
"resolution": "1080P",
"duration": 8,
"size": "16:9"
}'import requests
url = "https://api.openveer.com/v1/videos/generations"
payload = {
"model": "wan2.7",
"prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
"resolution": "1080P",
"duration": 8,
"size": "16:9"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())const url = "https://api.openveer.com/v1/videos/generations";
const payload = {
model: "wan2.7",
prompt: "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
resolution: "1080P",
duration: 8,
size: "16:9"
};
const headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
};
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(payload)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));package main
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)
func main() {
url := "https://api.openveer.com/v1/videos/generations"
payload := map[string]interface{}{
"model": "wan2.7",
"prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
"resolution": "1080P",
"duration": 8,
"size": "16:9",
}
jsonData, _ := json.Marshal(payload)
req, _ := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
req.Header.Set("Authorization", "Bearer <token>")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
public class Main {
public static void main(String[] args) throws Exception {
String url = "https://api.openveer.com/v1/videos/generations";
String payload = """
{
"model": "wan2.7",
"prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
"resolution": "1080P",
"duration": 8,
"size": "16:9"
}
""";
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(payload))
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
}
}<?php
$url = "https://api.openveer.com/v1/videos/generations";
$payload = [
"model" => "wan2.7",
"prompt" => "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
"resolution" => "1080P",
"duration" => 8,
"size" => "16:9"
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
"Authorization: Bearer <token>",
"Content-Type: application/json"
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>require 'net/http'
require 'json'
require 'uri'
url = URI("https://api.openveer.com/v1/videos/generations")
payload = {
model: "wan2.7",
prompt: "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
resolution: "1080P",
duration: 8,
size: "16:9"
}
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = "Bearer <token>"
request["Content-Type"] = "application/json"
request.body = payload.to_json
response = http.request(request)
puts response.bodyimport Foundation
let url = URL(string: "https://api.openveer.com/v1/videos/generations")!
let payload: [String: Any] = [
"model": "wan2.7",
"prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel",
"resolution": "1080P",
"duration": 8,
"size": "16:9"
]
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Bearer <token>", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = try? JSONSerialization.data(withJSONObject: payload)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error {
print("Error: \(error)")
return
}
if let data = data, let responseString = String(data: data, encoding: .utf8) {
print(responseString)
}
}
task.resume()using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var url = "https://api.openveer.com/v1/videos/generations";
var payload = @"{
""model"": ""wan2.7"",
""prompt"": ""A coastal road at sunset, slow-motion camera push-in, cinematic feel"",
""resolution"": ""1080P"",
""duration"": 8,
""size"": ""16:9""
}";
using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer <token>");
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
var result = await response.Content.ReadAsStringAsync();
Console.WriteLine(result);
}
}Response example
{
"code": 200,
"data": [
{
"status": "submitted",
"task_id": "task_01J9HA7JPQ9A0Z6JZ3V8M9W6PZ"
}
]
}{
"error": {
"code": 400,
"message": "Invalid request parameters",
"type": "invalid_request_error"
}
}{
"error": {
"code": 401,
"message": "Invalid authentication credentials",
"type": "authentication_error"
}
}{
"error": {
"code": 402,
"message": "Insufficient balance. Please top up your account",
"type": "payment_required"
}
}{
"error": {
"code": 429,
"message": "Rate limit exceeded. Please try again later",
"type": "rate_limit_error"
}
}{
"error": {
"code": 500,
"message": "Internal server error. Please try again later",
"type": "server_error"
}
}Authorization
Authorization stringAll API endpoints require Bearer Token authentication
Get your API Key:
Visit the API Key Management Page to get your API Key
Add it to the request header:
Authorization: Bearer YOUR_API_KEYMode Routing
wan2.7 is a unified entry for text-to-video and image-to-video. The backend automatically determines the mode based on the incoming parameters. Both modes are billed identically:
| Condition | Routes To | Mode Description |
|---|---|---|
Any of image_urls / image_with_roles / video_urls is provided |
Image-to-Video | First-frame / First-last frame / Video continuation |
| None of the above parameters provided | Text-to-Video | Generate video purely from text description |
Request Parameters
model stringVideo generation model name, fixed as wan2.7
nsfw_check booleanWhether to run content moderation before submitting the video task.
true: useomni-moderation-latestto review prompts and input imagesfalseor omitted: do not send a moderation request, adding no moderation cost or latency (default)
prompt stringVideo content description, up to 5000 characters
- Text-to-Video mode (when no image/video provided): required
- Image-to-Video mode: optional, but recommended to guide camera movement and actions
Example: "A cat chasing butterflies on the grass, bright sunshine, slow motion"
image_urls string">
Image URL array. Providing it automatically enters Image-to-Video mode
- 1 image: first-frame to video
- 2 images: first-last frame to video (1st = first frame, 2nd = last frame)
Use either this or image_with_roles
image_urls conflicts with audio_url; they cannot be provided at the same time
image_with_roles string">
Image array with roles, alternative to image_urls, used to precisely specify the role of each image
Fields for each object:
url(string): image URL (supports http/https)role(string): image role,first_frame/last_frame, defaultfirst_frame
Example:
[
{ "url": "https://cdn.example.com/start.jpg", "role": "first_frame" },
{ "url": "https://cdn.example.com/end.jpg", "role": "last_frame" }
]
image_with_roles conflicts with audio_url; they cannot be provided at the same time
video_urls string">
Video URL array. Providing it enters video continuation mode (only the 1st video is used)
video_urls conflicts with audio_url; they cannot be provided at the same time
Video constraints:
* Format: mp4, mov
* Duration: 2–10s
* Resolution: width and height in the range \[240, 4096] pixels
* Aspect ratio: 1:8 – 8:1
* File size: up to 100MB
negative_prompt stringNegative prompt describing unwanted content, up to 500 characters
Example: "blurry, distorted, low quality"
resolution stringVideo resolution
Options:
720P- Standard1080P- High definition (default)
duration integerVideo duration (seconds)
Supported range: 2 \~ 15 seconds
Default: 5
size stringAspect ratio, only effective in Text-to-Video mode (when no image/video provided)
Supported formats:
16:9- Landscape widescreen (default)9:16- Portrait1:1- Square4:3- Landscape3:4- Portrait
This parameter is ignored in Image-to-Video mode; the aspect ratio is determined automatically by the input image
audio_url stringCustom audio URL
- Text-to-Video mode: used as background music
- Image-to-Video mode: used as driving audio, synchronized with on-screen actions
Format: wav / mp3, duration 2-30 seconds, file size ≤ 15MB
audio_url conflicts with video_urls, image_urls, and image_with_roles; they cannot be provided at the same time
prompt_extend booleanWhether to enable intelligent prompt rewriting
Significantly improves results for short prompts, but increases processing time
Default: true
watermark booleanWhether to add "AI Generated" watermark to the generated video
true: add watermarkfalse: no watermark (default)
seed integerSeed integer used to control the randomness of generated content
Value range: integer ≥0
* For identical requests, the model generates different results when receiving different seed values (e.g., omitting seed)
* For identical requests, the model generates similar results when receiving the same seed value, but exact consistency is not guaranteed
Response
code integerResponse status code, 200 on success
data arraystatus stringTask status, submitted when initially submitted
task_id stringUnique task identifier for querying task status and results
Use Cases
Case 1: Text-to-Video (Simplest Request)
{
"model": "wan2.7",
"prompt": "A coastal road at sunset, slow-motion camera push-in, cinematic feel"
}Case 2: Text-to-Video (Full Parameters)
{
"model": "wan2.7",
"prompt": "A cat chasing butterflies on the grass, bright sunshine, slow motion",
"negative_prompt": "blurry, distorted, low quality",
"resolution": "1080P",
"duration": 8,
"size": "16:9",
"audio_url": "https://cdn.example.com/bgm.mp3",
"prompt_extend": true,
"watermark": false,
"seed": 42
}Case 3: First-Frame to Video
{
"model": "wan2.7",
"prompt": "The character slowly stands up and walks toward the camera",
"image_urls": ["https://cdn.example.com/person.jpg"],
"resolution": "1080P",
"duration": 8
}Case 4: First-Last Frame to Video
{
"model": "wan2.7",
"prompt": "The camera pans slowly from the beach to the mountaintop",
"image_urls": [
"https://cdn.example.com/beach.jpg",
"https://cdn.example.com/mountain.jpg"
],
"resolution": "1080P",
"duration": 10
}With 2 images: the 1st is the first frame, the 2nd is the last frame. You can also use
image_with_rolesfor precise specification.
Case 5: Video Continuation
{
"model": "wan2.7",
"prompt": "Continue walking forward, camera follows",
"video_urls": ["https://cdn.example.com/clip.mp4"],
"resolution": "1080P",
"duration": 8
}Case 6: Image + Driving Audio
{
"model": "wan2.7",
"prompt": "The character moves to the rhythm of the music",
"image_urls": ["https://cdn.example.com/dancer.jpg"],
"audio_url": "https://cdn.example.com/beat.mp3",
"resolution": "1080P",
"duration": 8
}Mode Selection Guide
| Requirement | Recommended Approach |
|---|---|
| Generate video from text only | Pass only prompt (no image/video) |
| Make an image "come alive" | Pass 1 image to image_urls |
| Control start and end frames | Pass 2 images to image_urls (first + last) |
| Extend an existing video | Pass video to video_urls |
| Make image move to music | Pass image + audio_url |
Query Task Results
Video generation is an async task that returns a task_id upon submission. Use the Get Task Status endpoint to query generation progress and results.
This documentation is built and hosted on Mintlify, a developer documentation platform.