curl --request POST \
--url https://api.apiyi.com/v1/videos \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form model=veo-3.1-fast-generate-preview \
--form 'prompt=Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks' \
--form input_reference=@example-fileimport requests
url = "https://api.apiyi.com/v1/videos"
files = { "input_reference": ("example-file", open("example-file", "rb")) }
payload = {
"model": "veo-3.1-fast-generate-preview",
"prompt": "Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('model', 'veo-3.1-fast-generate-preview');
form.append('prompt', 'Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks');
form.append('input_reference', '{
"fileName": "example-file"
}');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.apiyi.com/v1/videos', 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.apiyi.com/v1/videos",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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.apiyi.com/v1/videos"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.apiyi.com/v1/videos")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apiyi.com/v1/videos")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": "task_xxxxxxxxxxxxxxxx",
"task_id": "task_xxxxxxxxxxxxxxxx",
"object": "video",
"model": "veo-3.1-fast-generate-preview",
"status": "queued",
"progress": 0,
"created_at": 1775025000,
"completed_at": 1775025090
}VEO 3.1 공식 이미지-투-동영상 API
VEO 3.1 공식 이미지-투-동영상 API 레퍼런스 및 인터랙티브 Playground — 정적인 비주얼을 애니메이션으로 전환하기 위해 단일 input_reference 이미지를 multipart로 업로드합니다.
curl --request POST \
--url https://api.apiyi.com/v1/videos \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: multipart/form-data' \
--form model=veo-3.1-fast-generate-preview \
--form 'prompt=Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks' \
--form input_reference=@example-fileimport requests
url = "https://api.apiyi.com/v1/videos"
files = { "input_reference": ("example-file", open("example-file", "rb")) }
payload = {
"model": "veo-3.1-fast-generate-preview",
"prompt": "Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks"
}
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('model', 'veo-3.1-fast-generate-preview');
form.append('prompt', 'Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks');
form.append('input_reference', '{
"fileName": "example-file"
}');
const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
options.body = form;
fetch('https://api.apiyi.com/v1/videos', 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.apiyi.com/v1/videos",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: multipart/form-data"
],
]);
$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.apiyi.com/v1/videos"
payload := strings.NewReader("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
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.apiyi.com/v1/videos")
.header("Authorization", "Bearer <token>")
.body("-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apiyi.com/v1/videos")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request.body = "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"model\"\r\n\r\nveo-3.1-fast-generate-preview\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"prompt\"\r\n\r\nCamera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"input_reference\"; filename=\"example-file\"\r\nContent-Type: application/octet-stream\r\n\r\n{\r\n \"fileName\": \"example-file\"\r\n}\r\n-----011000010111000001101001--"
response = http.request(request)
puts response.read_body{
"id": "task_xxxxxxxxxxxxxxxx",
"task_id": "task_xxxxxxxxxxxxxxxx",
"object": "video",
"model": "veo-3.1-fast-generate-preview",
"status": "queued",
"progress": 0,
"created_at": 1775025000,
"completed_at": 1775025090
}Bearer sk-xxx), 참조 이미지를 업로드한 다음 prompt를 입력하고, 모델 / 초 / 해상도를 선택한 뒤 전송합니다. Default 그룹은 작동합니다 — 별도의 그룹 전환이 필요하지 않습니다.- Content-Type은
multipart/form-data여야 합니다 (JSON 아님) - 참조 이미지는 1장만 지원됩니다; 필드명은
input_reference으로 고정됩니다. 여러 이미지를 제출하면 첫 번째만 유지됩니다 - 원격 URL은 허용되지 않습니다 — 파일 업로드 또는 Base64여야 합니다
- 허용 형식:
image/jpeg/image/png/image/webp - 길이 필드는
seconds로 명명해야 하며(duration아님),"4"/"6"/"8"형식의 문자열이어야 합니다duration로 지정하면 조용히 무시되고 기본 4초로 되돌아갑니다. 숫자를 전달하면 실패합니다 - 1080p / 4k에서는
seconds가"8"여야 합니다
-fl 시리즈를 사용하십시오.코드 예제
Python (OpenAI SDK · low-level client.post)
{/* OpenAI SDK has no videos.create method; /v1/videos is a custom path, use low-level client.post() */}
from openai import OpenAI
import time
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.apiyi.com/v1"
)
# Step 1: multipart upload (low-level client.post handles multipart boundary)
with open("./lighthouse.png", "rb") as f:
resp = client.post(
"/videos",
body=None,
files={
"input_reference": ("lighthouse.png", f, "image/png")
},
extra_body={
"model": "veo-3.1-fast-generate-preview",
"prompt": "Camera slowly rises from the base of the lighthouse to the top, dusk lighting, ocean ambience",
"seconds": "8", # must be string
"size": "1280x720",
"resolution": "720p",
"aspectRatio": "16:9"
},
cast_to=dict
)
task_id = resp.get("task_id") or resp["id"]
print(f"Task ID: {task_id}, status: {resp['status']}")
# Step 2: poll (up to 3 minutes)
deadline = time.time() + 180
while time.time() < deadline:
s = client.get(f"/videos/{task_id}", cast_to=dict)
print(f"Status: {s['status']}, progress: {s.get('progress', 0)}%")
if s["status"] == "completed":
break
if s["status"] == "failed":
raise RuntimeError(f"Generation failed: {s}")
time.sleep(8)
# Step 3: download (with retry)
import urllib.request, urllib.error
time.sleep(4)
for i in range(8):
try:
req = urllib.request.Request(
f"https://api.apiyi.com/v1/videos/{task_id}/content",
headers={"Authorization": "Bearer sk-your-api-key"}
)
with urllib.request.urlopen(req, timeout=180) as r, open("output.mp4", "wb") as f:
while chunk := r.read(1 << 16):
f.write(chunk)
break
except urllib.error.HTTPError as e:
# 400 = status just flipped to completed (window up to ~20 s): keep waiting; 502 etc.: one more try at most
if i == 7 or (e.code != 400 and i >= 1):
raise
time.sleep(4)
print("Saved: output.mp4")
Python (requests + multipart)
import requests
import time
API_KEY = "sk-your-api-key"
BASE_URL = "https://api.apiyi.com/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# Step 1: multipart upload of reference image + form fields
with open("./lighthouse.png", "rb") as f:
resp = requests.post(
f"{BASE_URL}/videos",
headers=HEADERS, # do not set Content-Type manually; requests handles multipart boundary
data={
"model": "veo-3.1-fast-generate-preview",
"prompt": "Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks",
"seconds": "8", # string, not number
"size": "1280x720",
"resolution": "720p",
"aspectRatio": "16:9",
"seed": "20260521"
},
files={
"input_reference": ("lighthouse.png", f, "image/png")
},
timeout=60 # multipart upload of large images may be slow
).json()
task_id = resp.get("task_id") or resp["id"]
print(f"Task ID: {task_id}")
# Step 2: poll
deadline = time.time() + 180
while time.time() < deadline:
s = requests.get(f"{BASE_URL}/videos/{task_id}", headers=HEADERS).json()
print(f"Status: {s['status']}, progress: {s.get('progress', 0)}%")
if s["status"] == "completed":
break
if s["status"] == "failed":
raise RuntimeError(s)
time.sleep(8)
# Step 3: download (retry the 400 right after completed)
time.sleep(4)
for i in range(8):
try:
with requests.get(
f"{BASE_URL}/videos/{task_id}/content",
headers=HEADERS, stream=True, timeout=180
) as r:
r.raise_for_status()
with open("output.mp4", "wb") as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
break
except requests.HTTPError as e:
# 400 = status just flipped to completed (window up to ~20 s): keep waiting; 502 etc.: one more try at most
if i == 7 or (e.response.status_code != 400 and i >= 1):
raise
time.sleep(4)
print("Saved: output.mp4")
cURL (multipart upload)
{/* Just want to check/download with an existing task_id? See the "Already have a task_id?" section below */}
{/* Step 1: multipart upload (input_reference uses @ to reference a local file) */}
RESP=$(curl -sS -X POST "https://api.apiyi.com/v1/videos" \
-H "Authorization: Bearer sk-your-api-key" \
-F "model=veo-3.1-fast-generate-preview" \
-F "prompt=Camera slowly rises from the base of the lighthouse to the top, dusk lighting" \
-F "seconds=8" \
-F "size=1280x720" \
-F "resolution=720p" \
-F "aspectRatio=16:9" \
-F "input_reference=@./lighthouse.png;type=image/png")
TASK_ID=$(echo "$RESP" | python3 -c 'import sys,json;print((lambda d: d.get("task_id") or d["id"])(json.load(sys.stdin)))')
echo "task_id=$TASK_ID"
{/* Step 2: poll */}
while :; do
S=$(curl -sS -H "Authorization: Bearer sk-your-api-key" "https://api.apiyi.com/v1/videos/$TASK_ID")
ST=$(echo "$S" | python3 -c 'import sys,json;print(json.load(sys.stdin)["status"])')
echo "status=$ST"
[ "$ST" = "completed" ] && break
[ "$ST" = "failed" ] && { echo "$S"; exit 1; }
sleep 8
done
{/* Step 3: download (--retry covers occasional 400 right after status=completed) */}
sleep 4
curl -fsSL --retry 7 --retry-delay 4 --retry-all-errors \
-H "Authorization: Bearer sk-your-api-key" \
"https://api.apiyi.com/v1/videos/$TASK_ID/content" \
-o output.mp4
ls -lh output.mp4
Node.js (native fetch + FormData)
import fs from 'node:fs';
import { FormData, File } from 'undici';
const API_KEY = 'sk-your-api-key';
const BASE_URL = 'https://api.apiyi.com/v1';
// Step 1: multipart upload
const buffer = fs.readFileSync('./lighthouse.png');
const form = new FormData();
form.append('model', 'veo-3.1-fast-generate-preview');
form.append('prompt', 'Camera slowly rises from the base of the lighthouse to the top, dusk lighting');
form.append('seconds', '8'); // string
form.append('size', '1280x720');
form.append('resolution', '720p');
form.append('aspectRatio', '16:9');
form.append('input_reference', new File([buffer], 'lighthouse.png', { type: 'image/png' }));
const submitResp = await fetch(`${BASE_URL}/videos`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${API_KEY}` }, // do not set Content-Type manually
body: form
});
const submitData = await submitResp.json();
const task_id = submitData.task_id || submitData.id;
console.log(`Task ID: ${task_id}`);
// Step 2: poll
let status = 'queued';
while (status !== 'completed' && status !== 'failed') {
await new Promise(r => setTimeout(r, 8000));
const s = await (await fetch(`${BASE_URL}/videos/${task_id}`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
})).json();
status = s.status;
console.log(`Status: ${status}, progress: ${s.progress ?? 0}%`);
}
if (status === 'failed') throw new Error('Generation failed');
// Step 3: download (with retry)
await new Promise(r => setTimeout(r, 4000));
let videoBuffer;
for (let i = 0; i < 8; i++) {
try {
const resp = await fetch(`${BASE_URL}/videos/${task_id}/content`, {
headers: { 'Authorization': `Bearer ${API_KEY}` }
});
if (!resp.ok) throw Object.assign(new Error(`HTTP ${resp.status}`), { status: resp.status });
videoBuffer = Buffer.from(await resp.arrayBuffer());
break;
} catch (e) {
if (i === 7 || (e.status !== 400 && i >= 1)) throw e; // 400: keep waiting; 502 etc.: one more try at most
await new Promise(r => setTimeout(r, 4000));
}
}
fs.writeFileSync('output.mp4', videoBuffer);
console.log('Saved: output.mp4');
Browser JavaScript (file input upload)
{/* Demo only; route through a backend proxy in production to avoid Key leakage */}
const fileInput = document.querySelector('input[type=file]');
const file = fileInput.files[0];
const form = new FormData();
form.append('model', 'veo-3.1-fast-generate-preview');
form.append('prompt', 'Animate this scene with a gentle camera push-in and natural ambient sound');
form.append('seconds', '4');
form.append('size', '720x1280');
form.append('resolution', '720p');
form.append('aspectRatio', '9:16');
form.append('input_reference', file);
const submitResp = await fetch('https://api.apiyi.com/v1/videos', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk-your-api-key' },
body: form
});
const submitData = await submitResp.json();
const task_id = submitData.task_id || submitData.id;
console.log('Task ID:', task_id);
{/* After polling completes, route the /content endpoint through your backend proxy */}
이미 task_id가 있으신가요? 바로 복사해 사용하는 cURL 명령어 2개
이미task_id가 있는 경우(작업 제출 시 반환되었거나 콘솔 로그에서 확인 가능), 아래의 두 자리표시자만 변경하여 실행하십시오:
sk-your-api-key→ 사용자의 APIYI 키task_xxxxxxxxxxxxxxxx→ 사용자의 작업 ID
1. 작업 상태 확인
curl "https://api.apiyi.com/v1/videos/task_xxxxxxxxxxxxxxxx" \
-H "Authorization: Bearer sk-your-api-key"
status: "completed"가 표시되면 다운로드할 수 있습니다. in_progress가 표시되면 몇 초 기다린 후 다시 확인하십시오.
2. 동영상 다운로드 (output.mp4로 저장)
curl -fL --retry 7 --retry-delay 4 --retry-all-errors \
"https://api.apiyi.com/v1/videos/task_xxxxxxxxxxxxxxxx/content" \
-H "Authorization: Bearer sk-your-api-key" \
-o output.mp4
/content 엔드포인트에는 Authorization 헤더가 필요합니다. 브라우저 주소창에서 URL을 직접 열면 401이 반환됩니다. -f --retry 7 --retry-delay 4 --retry-all-errors는 status가 completed(으)로 전환된 직후 발생하는 400 오류를 처리합니다(최대 약 20초). -f이 없으면 curl은 400을 성공으로 간주하여 오류 JSON을 output.mp4에 기록합니다. --retry-all-errors이 없으면 --retry는 400 오류를 전혀 재시도하지 않습니다(curl 7.71 이상 필요).매개변수 참조
| 매개변수 | 형식 | 필수 | 기본값 | 설명 |
|---|---|---|---|---|
input_reference | file | Yes | — | 참조 이미지 파일입니다. 필드명은 고정이며, 이미지는 1장만 허용됩니다, image/jpeg / image/png / image/webp를 지원합니다. 원격 URL은 허용되지 않습니다 |
model | string | Yes | — | veo-3.1-fast-generate-preview ($0.3/req) 또는 veo-3.1-generate-preview ($1.2/req) |
prompt | string | Yes | — | 장면이 어떻게 애니메이션될지 설명합니다: 카메라 움직임, 객체 동작, 조명, 스타일. generateAudio를 전달하지 마십시오, 오디오 의도는 prompt에 넣으십시오 |
seconds | string | No | "8" | "4" / "6" / "8". 필드는 seconds이며, duration가 아닙니다 (duration로 지정하면 조용히 무시되며 4초로 대체됩니다). 1080p/4k는 "8"로 설정해야 합니다 |
size | string | No | 1280x720 | 출력 픽셀 |
resolution | string | No | 720p | 720p / 1080p / 4k |
aspectRatio | string | No | 16:9 | 16:9 (가로) / 9:16 (세로) |
seed | int | No | — | 랜덤 시드(multipart 폼 필드이며, 문자열로 인코딩된 숫자도 괜찮습니다) |
- JSON 모드에서는
metadata.*아래에 중첩됩니다(예:metadata.resolution) - Multipart 모드에서는 폼 필드로 평면화됩니다(
resolution/aspectRatio/seed를 직접 사용) - 위의 코드 샘플은 이미 multipart 규칙을 사용합니다
input_reference를 JSON 본문 안의 Base64 문자열로 보내는 경우 — multipart 파일 필드를 사용해야 합니다- 필드명을
image/reference/input_image로 지정하는 경우 — 반드시input_reference여야 합니다 - 이미지를 2장 보내는 경우 — 서버는 첫 번째만 유지하고 두 번째는 조용히 버립니다
- 원격 URL(
https://cdn.../img.png)을 보내는 경우 — 허용되지 않으며, 파일 또는 Base64를 사용해야 합니다
응답 형식
응답 구조는 텍스트-동영상과 동일합니다: 1단계는task_id + status: "queued"을 반환하고, 2단계 폴링은 status + 대략적인 progress을 반환하며, 3단계는 /content에서 MP4 바이너리를 다운로드합니다.
{
"id": "task_xxxxxxxxxxxxxxxx",
"task_id": "task_xxxxxxxxxxxxxxxx",
"object": "video",
"model": "veo-3.1-fast-generate-preview",
"status": "queued",
"progress": 0,
"created_at": 1775025000
}
- 작업 ID는
id에서 가져옵니다(제출 응답에는 동일한 값을 가진task_id이 포함될 수도 있지만, 폴링 응답에는id만 포함됩니다) - 기준 소스(source of truth)로
GET /v1/videos/{task_id}/content에서 다운로드하십시오. 완료 응답에는 약 24시간 동안 유효한video_url이 포함될 수도 있으나, 모든 작업에서 보장되는 것은 아닙니다 progress은 선형적으로 증가하지 않고 몇 가지 고정된 단계 사이에서만 건너뜁니다/content은status이(가)completed(으)로 전환된 직후 가끔 400을 반환합니다. 4초 후 다시 시도하십시오- 이미지-동영상 작업은 일반적으로 동급의 텍스트-동영상 작업보다 10–30% 더 오래 걸립니다(추가 이미지 인코딩 단계 포함)
completed에 도달할 때 모델 이름별로 요청당 청구됩니다(input_reference 제공 여부와 무관하며, fast $0.3 / standard $1.2). POST 제출, 폴링 및 다운로드 자체는 과금되지 않으며, 실패한 작업 역시 과금되지 않습니다.인증
API Key from APIYI console (Default group + Pay-per-request or Pay-as-you-go Priority Token; pure Pay-as-you-go not supported)
본문
Model ID (per-request billing):
veo-3.1-fast-generate-preview— $0.3/requestveo-3.1-generate-preview— $1.2/request
veo-3.1-fast-generate-preview, veo-3.1-generate-preview Video generation prompt. Focus on how the scene should animate: camera motion, object action, lighting, audio atmosphere. Do not pass generateAudio — audio intent goes in the prompt.
"Camera slowly rises from the base of the lighthouse to the top, dusk lighting, waves lapping the rocks"
Reference image file. Field name is fixed as input_reference, only 1 image supported.
Accepted formats: image/jpeg / image/png / image/webp. Remote URLs not accepted — must be a file upload or Base64.
Video length. The field name is seconds (not duration), a string enum: "4" / "6" / "8". Sending duration is silently ignored and falls back to the default 4 sec. Must be "8" at 1080p / 4k.
4, 6, 8 Output pixel dimensions; lower precedence than resolution
1280x720, 720x1280, 1920x1080, 1080x1920, 3840x2160, 2160x3840 Resolution tier (multipart mode flattens this as a top-level form field; higher precedence than size)
720p, 1080p, 4k Aspect ratio: 16:9 landscape (default) or 9:16 portrait
16:9, 9:16 Random seed (multipart form field; string-encoded number is fine). Fixed seed clusters outputs in style but does not byte-reproduce.
"20260521"
Negative prompt; recommended "blurry, watermark, distorted, low quality"
"blurry, watermark, distorted, low quality"
응답
Task submitted; returns task_id and queued status
Task ID (matches task_id; downstream should standardize on task_id)
"task_xxxxxxxxxxxxxxxx"
Task ID for subsequent polling and download
"task_xxxxxxxxxxxxxxxx"
Object type, fixed to video
"video"
Model ID used for this task
"veo-3.1-fast-generate-preview"
Task status:
queued— submitted, awaiting processingin_progress— generatingcompleted— done, downloadable (/v1/videos/{task_id}/content)failed— failed (not billed), retry possible
queued, in_progress, completed, failed "queued"
Generation progress (coarse-grained, jumps only between 0 / 50 / 100)
0
Task creation Unix timestamp (seconds)
1775025000
Task completion Unix timestamp (seconds); only present for completed status
1775025090
이 페이지가 도움이 되었나요?