HiAPI
블로그

튜토리얼

PixVerse V6 이미지-투-비디오 API: 바로 실행 가능한 curl 및 Python 예제

Oct 20, 2026
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로 설정하세요. 강제로 켜지거나 꺼지지 않습니다.

이번 탐색에서는 클립을 렌더링하지 않았으므로 이 가이드는 모션 품질이나 모델이 입력 프레임을 충실히 보존하는 정도를 주장하지 않습니다—이는 엔드포인트가 강제하는 정확한 요청 계약만을 기록합니다.

관련 콘텐츠

자주 묻는 질문

이미지-투-비디오에는 왜 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만 허용합니다.

영구 AI 아티팩트로 빌드 시작하기

API 키를 받아 태스크 기반의 하나의 API로 이미지, 비디오, 오디오 모델을 호출하세요.

API 문서 보기