튜토리얼
PixVerse V6 이미지-투-비디오 API: 바로 실행 가능한 curl 및 Python 예제
- 모델
- pixverse-v6
hiapi에서 pixverse-v6/image-to-video를 사용해 정적 이미지를 애니메이션으로 만들려면 POST /v1/tasks 호출 한 번과 폴링 한 번이면 됩니다. 이는 플랫폼의 모든 생성 모델이 사용하는 비동기 작업 패턴과 완전히 동일합니다. 텍스트-투-비디오 엔드포인트와의 차이는 입력에 있습니다. 시작 프레임(image_url)과 그것이 어떻게 움직여야 하는지 설명하는 프롬프트를 제공해야 합니다. 이 가이드에서는 바로 복사해 붙여넣을 수 있는 curl 및 Python 예제, 이 엔드포인트가 실제로 검증하는 입력 필드, 그리고 텍스트-투-비디오에서 넘어온 사람이 빠지기 쉬운 의외의 함정 하나를 소개합니다.
필요한 준비물
- hiapi API 키. 콘솔에서 생성하고
Authorization: Bearer sk-<your-key>로 전송하세요. 헤더 형식은 인증 문서를 참고하세요. - 모델 ID는
pixverse-v6/image-to-video입니다(슬래시 유지—ID의 일부이며 URL 경로가 아닙니다). 이는pixverse-v6/text-to-video와 다른 모델 ID입니다. - 첫 프레임으로 사용할 공개적으로 접근 가능한 이미지 URL. 플랫폼이 서버 측에서 해당 이미지를 가져오므로
localhost나 비공개 버킷 링크는 사용할 수 없습니다. 첫 프레임은 API가 GET으로 접근할 수 있는 위치에 호스팅하세요. - curl 사용에는 아무것도 설치할 필요가 없습니다. Python 예제의 경우 표준 라이브러리와
requests만 있으면 됩니다.
PixVerse V6 이미지-투-비디오는 제공한 정적 이미지를 시작 프레임으로 삼아 1–15초 클립으로 애니메이션화합니다. 통합 비동기 작업 API를 통해 실행됩니다. 작업을 제출하고, 결과를 폴링한 뒤, 출력 URL이 만료되기 전에 다운로드하세요.
최소 동작 요청(curl)
POST /v1/tasks에 작업을 제출하세요. image_url과 prompt는 모두 필수입니다:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "pixverse-v6/image-to-video",
"input": {
"image_url": "https://cdn.example.com/your-first-frame.jpg",
"prompt": "Slow push-in; the subject turns toward the camera and smiles, soft breeze in the hair",
"duration": 5,
"resolution": "720p"
}
}'
응답은 작업 ID를 반환합니다:
{ "code": 200, "data": { "taskId": "a1b2c3d4-...." } }
그런 다음 GET /v1/tasks/<taskId>를 폴링하여 data.status가 success가 될 때까지 기다리세요:
curl -s https://api.hiapi.ai/v1/tasks/a1b2c3d4-.... \
-H "Authorization: Bearer sk-<your-key>"
성공 시 완료된 비디오 URL은 data.output[0].url에 있습니다:
{
"code": 200,
"data": {
"status": "success",
"output": [{ "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1760000000 }]
}
}
이 출력 URL은 임시입니다—expireAt 타임스탬프가 있습니다. 즉시 .mp4를 다운로드하여 자체 버킷에 저장하세요. 직접 핫링크하지 마세요.
Python에서 동일한 흐름
import time, requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<your-key>", "Content-Type": "application/json"}
def create_task():
payload = {
"model": "pixverse-v6/image-to-video",
"input": {
"image_url": "https://cdn.example.com/your-first-frame.jpg",
"prompt": "Slow push-in; the subject turns toward the camera and smiles",
"duration": 5,
"resolution": "720p",
},
}
r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
r.raise_for_status()
data = r.json()
task_id = (data.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"create failed: {data}") # 400s echo the exact bad field
return task_id
def wait_for(task_id, timeout_s=600):
deadline = time.time() + timeout_s
while time.time() < deadline:
try:
r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30)
task = (r.json().get("data") or {})
except requests.RequestException:
time.sleep(5) # one transient network blip should not abort the whole poll
continue
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
raise RuntimeError(f"task failed: {task.get('error')}")
time.sleep(5) # still pending — keep the SAME task_id, re-poll
raise TimeoutError(task_id)
task_id = create_task()
url = wait_for(task_id)
video = requests.get(url, timeout=120).content
open("out.mp4", "wb").write(video)
print("saved out.mp4")
폴링 루프는 success와 fail을 명시적으로 확인하고 다른 모든 상태에 대해서는 계속 기다리므로, 작업이 렌더링 중에 보고하는 중간 상태 레이블이 무엇이든 견고하게 처리합니다. 폴링 요청이 한 번 실패하면 잠시 기다린 후 동일한 저장된 task_id로 다시 폴링하세요. 재제출하지 마세요—재제출하면 두 번째 렌더링 비용이 발생합니다.
pixverse-v6/image-to-video가 실제 검증하는 파라미터
다음은 라이브 엔드포인트가 실제로 허용하는 필드입니다. 유효하지 않은 값을 보내고 검증 오류를 읽어 하나하나 확인한 뒤, 모델 문서와 교차 검증했습니다:
| 필드 | 타입 | 값 / 범위 | 설명 |
|---|---|---|---|
image_url |
string | 공개 이미지 URL | 필수. 첫 프레임. 단일 URL 문자열—배열이 아닙니다. |
prompt |
string | — | 필수. 해당 프레임에 적용할 움직임을 설명합니다. |
duration |
integer | 1–15, 기본값 5 |
단위는 초. 정수여야 하며 문자열이 아닙니다. |
resolution |
string | 360p, 540p, 720p, 1080p |
출력 해상도. |
negative_prompt |
string | — | 선택 사항. 회피할 콘텐츠. |
seed |
integer | — | 선택 사항. 재현 가능한 결과를 위해 재사용합니다. |
style |
string | anime, 3d_animation, clay, comic, cyberpunk |
선택적 사전 설정 스타일. |
generate_audio |
boolean | true / false, 기본값 false |
선택 사항. 생성된 오디오 트랙/앰비언트 사운드 켜기/끄기. |
여기에는 aspect_ratio 필드가 없습니다. 이는 여러분이 보았을 수 있는 텍스트-투-비디오 요청과의 유일한 실질적 차이이므로 기억해 둘 가치가 있습니다(아래 참조).
프로덕션 시 유의 사항
aspect_ratio없음—출력 형상은 입력 이미지를 따릅니다. 텍스트-투-비디오 엔드포인트는aspect_ratio열거형을 허용하지만 이 엔드포인트는 이를 거부합니다. 첫 프레임을 제공하기 때문에 클립은 해당 프레임의 크기를 상속합니다. 9:16 세로 클립이 필요하면 제출 전에image_url을 9:16으로 자르거나 패딩하세요—이를 덮어쓸 비율 조절 노브는 없습니다.- 요청 구조는 폐쇄적입니다. 위 표에 없는 모든 필드는
invalid input: <root>: additional properties '<field>' not allowed오류로 거부됩니다. 오타나 추측한 필드는 조용히 무시되지 않고 제출 시 큰 소리로 실패합니다.first_frame,image,input_image,motion_mode,camera_movement등의 필드는 모두 거부됩니다—시작 이미지는image_url에, 카메라 움직임은prompt텍스트에 작성합니다. duration은 정수이며, 문자열("6")을 허용하는 플랫폼의 일부 다른 비디오 모델과 다릅니다."5"를 보내면invalid input: duration: got string, want integer가 반환됩니다. 범위를 벗어난 값은duration: maximum: got 999, want 15처럼 경계를 직접 보고합니다.- 오류는 한 번에 한 필드씩 플랫 형식으로 반환됩니다:
{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: image_url: missing required field \"image_url\""}. 보고된 필드를 수정하고 다시 제출하세요. 다음 유효하지 않은 필드(있는 경우)는 다음 호출에서 나타납니다. - 작업 실패도 HTTP 200을 반환합니다. 실패 정보는 응답 본문에
data.status: "fail"형식으로 있습니다—HTTP 상태 코드뿐 아니라 상태 필드도 확인하세요. 플랫폼이 가져올 수 없는 이미지 URL이 흔한 원인이므로 첫 프레임이 공개 상태인지 먼저 확인하세요. - 초 단위로 과금되며 해상도와 길이에 따라 증가하므로 1080p/15s 클립은 540p/3s 클립보다 훨씬 비쌉니다. 대량 생성 전에 가격 페이지에서 현재 요율을 확인하세요.
내가 검증한 것(그리고 검증하지 않은 것)
pixverse-v6/image-to-video의 라이브 /v1/tasks 엔드포인트에 의도적으로 잘못된 값을 보내고 API 자체의 검증 응답을 읽어 입력 계약을 파악했습니다—콜백도 없고 렌더링 비용도 발생하지 않은 읽기 전용 스키마 탐색이었습니다. 기억할 가치가 있는 구체적 발견:
image_url은 필수 첫 프레임 필드이며 단일 문자열이고 배열이 아닙니다. 숫자를 보내면image_url: got number, want string을 반환하고, 생략하면missing required field "image_url"을 반환합니다. 추측할 수 있는 대체 필드(first_frame,image,input_image)는 모두 알 수 없는 속성으로 거부됩니다.- 이 엔드포인트는
aspect_ratio를 거부합니다(additional properties 'aspect_ratio' not allowed).pixverse-v6/text-to-video에서는 유효함에도 불구하고요. 이것이 이미지-투-비디오 요청이 텍스트-투-비디오와 구체적으로 다른 이유입니다. 출력 형상은 파라미터가 아니라 여러분의 프레임에 의해 결정됩니다. generate_audio는 진짜 불리언 스위치입니다(기본값false)—문자열을 보내면generate_audio: got string, want boolean을 반환합니다. 소리가 필요하면true로 설정하세요. 강제로 켜지거나 꺼지지 않습니다.
이번 탐색에서는 클립을 렌더링하지 않았으므로 이 가이드는 모션 품질이나 모델이 입력 프레임을 충실히 보존하는 정도를 주장하지 않습니다—이는 엔드포인트가 강제하는 정확한 요청 계약만을 기록합니다.
관련 콘텐츠
- PixVerse V6 이미지-투-비디오—모델 페이지
- PixVerse V6 이미지-투-비디오—API 문서
- 작업 생성 및 작업 상세 조회 참고
- 인증
- 가격
- hiapi의 다른 이미지-투-비디오 튜토리얼: hailuo-2.3 및 Grok Imagine 1.5
자주 묻는 질문
이미지-투-비디오에는 왜 aspect_ratio가 없나요? 클립이 여러분의 image_url 프레임으로 시작해 그 크기를 상속하기 때문입니다. 출력 비율을 제어하려면 제출 전에 입력 이미지 크기를 조정하거나 잘라내세요—이 엔드포인트는 aspect_ratio를 알 수 없는 필드로 거부합니다.
image_url은 여러 이미지를 허용하나요? 아닙니다. 이 엔드포인트에서는 단일 URL 문자열입니다. 배열을 전달하면 검증에 실패합니다. 시작 프레임만 설정합니다.
duration의 단위는 초인가요, 프레임인가요? 초입니다—1에서 15 사이의 정수, 기본값 5. 정수여야 하며 문자열 "5"는 거부됩니다.
텍스트-투-비디오 엔드포인트와 무엇이 다른가요? pixverse-v6/image-to-video는 제공한 프레임을 애니메이션화합니다(image_url + prompt, aspect_ratio 없음). pixverse-v6/text-to-video는 별도 모델 ID이며 프롬프트만으로 생성하고 aspect_ratio를 실제로 허용합니다. 움직이게 하고 싶은 정확한 오프닝 정지 프레임이 이미 있을 때 이미지-투-비디오를 사용하세요.
왜 요청이 "additional properties not allowed" 오류로 실패하나요? 스키마에 없는 필드를 보냈기 때문입니다. 입력은 image_url, prompt, duration, resolution, negative_prompt, seed, style, generate_audio만 허용합니다.
관련 글
모든 아티클 보기 →-
튜토리얼
HiAPI API로 hailuo-2.3-fast/image-to-video 호출하는 방법: curl과 Python 실전
빠르고 저렴한 이미지-투-비디오 등급의 첫 실행 요청 — 모델 ID부터 MP4 다운로드까지
-
튜토리얼
HiAPI API로 hailuo-2.3/text-to-video를 호출하는 방법: curl, Python 및 실행 가능한 요청 예시
-
튜토리얼
HiAPI에서 Kandinsky 6.0 Pro 텍스트-투-비디오 사용하기: curl 및 Python 튜토리얼
요청 우선 실전 데모: 프롬프트에서 비디오 클립까지의 호출 구성, 요청 제출, 완료 상태 폴링 및 결과 다운로드