HiAPI
블로그

튜토리얼

vidu-q3-ad reference-to-video API: curl, Python 및 바로 실행 가능한 요청

Oct 20, 2026
vidu-q3-ad reference-to-video API: curl, Python 및 바로 실행 가능한 요청

무엇을 구축하게 되는가

hiapi의 비동기 /v1/tasks API에서 reference-to-video 호출을 한 번 실행하여 1–7장의 제품 정지 이미지를 네이티브 오디오가 포함된 짧은 영상 광고로 변환합니다. vidu-q3-ad/reference-to-video는 Vidu Q3의 광고 지향 티어로, 제품 참조 이미지를 업로드하고 장면 설명을 작성하면 모델이 3–15초 MP4를 반환하며, 스마트 편집, 카메라 무빙, 생성된 음향 효과가 내장되어 있습니다. 별도로 제공해야 할 오디오 트랙은 없습니다.

POST를 한 번 제출한 다음 (또는 콜백을 받거나) 작업이 완료될 때까지 폴링하고 MP4를 다운로드하면 됩니다. 먼저 hiapi 콘솔에서 키를 발급받으세요. 아래 모든 요청은 Authorization: Bearer sk-...를 사용합니다.

그대로 복사해야 할 세 가지:

  • 제출 엔드포인트: POST https://api.hiapi.ai/v1/tasks
  • 폴링 엔드포인트: GET https://api.hiapi.ai/v1/tasks/{taskId}
  • 모델 ID: vidu-q3-ad/reference-to-video — 슬래시와 -ad 접미사 모두 생략할 수 없습니다. vidu-q3-mix와 vidu-q4-preview는 다른 엔드포인트입니다.

입력 스키마 (실시간 프로빙으로 확인)

필드 필수 여부 유형 설명
prompt 예 string 장면 설명. 예: "참조 이미지 1의 시계"처럼 번호로 제품을 지칭
reference_image_urls 예 array, 1–7 제품 정지 이미지의 공개 URL (서버가 가져감)
duration 예 integer, 3–15 초 단위. 반드시 정수여야 합니다 (4.5는 거부됨)
size 아니오 enum (10개 값) 동시에 종횡비와 720/1080 등급을 결정합니다. 기본값은 1280*720

검증기는 매우 엄격합니다. 위 목록에 없는 필드는 모두 즉시 거부됩니다. 특히 주목할 두 가지 거부 사례가 있는데, 다른 hiapi 비디오 모델에서 넘어온 사람이라면 모두 여기서 실수하기 쉽습니다.

  • aspect_ratio와 resolution 모두 거부됩니다. 거의 모든 다른 hiapi 비디오 엔드포인트가 이 두 필드를 사용하지만 q3-ad는 사용하지 않습니다. 크기는 size로만 제어할 수 있습니다.
  • reference_audio_urls 역시 거부됩니다. 음성 클립을 받을 수 있는 Vidu Q4의 reference-to-video 티어와 달리, q3-ad에는 오디오 입력이 없습니다. 사운드트랙은 네이티브로 생성됩니다. (이 점을 어떻게 확인했는지는 아래 검증 섹션을 참고하세요.)

size 선택 방법

size는 고정 집합에서 나온 width*height 문자열입니다. 다섯 가지 종횡비 × 두 가지 품질 등급의 그리드로 읽으면 됩니다.

종횡비 720 등급 1080 등급
16:9 가로 1280*720 1920*1080
9:16 세로 720*1280 1080*1920
1:1 정사각 1280*1280 1808*1808
4:3 1280*960 1920*1440
3:4 960*1280 1440*1920

게재 위치에 따라 행을 선택하고 (Reels와 TikTok은 세로 720*1280 / 1080*1920, YouTube 인스트림 광고는 가로 행), 화질과 예산의 균형에 따라 열을 선택하세요. 과금은 출력 초 수를 기준으로 하며, 등급이 초당 단가를 결정합니다. 자세한 내용은 가격을 참고하세요. 최소 과금은 3초 클립입니다.

최소 요청 (curl)

두 단계: 제출 후 폴링.

# 1) 제출 — taskId를 반환합니다
curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-your-key" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "vidu-q3-ad/reference-to-video",
    "input": {
      "prompt": "참조 이미지 1의 티타늄 스마트워치 제품 광고: 어두운 반사 받침대 위에서 천천히 회전하며, 강한 빛 줄기가 브러시드 케이스 위를 왼쪽에서 오른쪽으로 훑고 지나가고, 화면은 어둡게 유지되며, 카메라는 낮은 히어로 앵글을 유지합니다. 상업용 조명, 높은 대비, 매크로 디테일.",
      "reference_image_urls": [
        "https://your-cdn.com/watch-front.png",
        "https://your-cdn.com/watch-side.png"
      ],
      "duration": 5,
      "size": "1280*720"
    }
  }'
# -> {"data":{"taskId":"..."}}

# 2) data.status가 "success" 또는 "fail"이 될 때까지 폴링
curl -s https://api.hiapi.ai/v1/tasks/THE_TASK_ID \
  -H "Authorization: Bearer sk-your-key"
# 성공 -> data.status == "success", data.output[0].url이 MP4

참조 이미지 URL은 공개적으로 접근 가능해야 합니다. 작업이 서버 측에서 이미지를 가져오므로 localhost나 몇 초 후 만료되는 서명 URL은 사용할 수 없습니다.

Python: 제출, 폴링, 다운로드

import time
import requests  # 또는 urllib/subprocess를 사용해 의존성 없이 유지

API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-your-key", "Content-Type": "application/json"}

def submit():
    payload = {
        "model": "vidu-q3-ad/reference-to-video",
        "input": {
            "prompt": "참조 이미지 1의 스니커가 조명이 켜진 턴테이블 위에서 회전하는 광고 샷, "
                      "느린 푸시인, 부드러운 림 라이트, 제품 히어로 프레이밍.",
            "reference_image_urls": ["https://your-cdn.com/sneaker.png"],
            "duration": 5,
            "size": "1080*1920",   # Reels / TikTok용 세로 1080p
        },
    }
    body = requests.post(API, headers=HEADERS, json=payload, timeout=60).json()
    task_id = (body.get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"submit rejected: {body}")   # 400이 여기로 떨어집니다
    return task_id

def wait(task_id, timeout_s=600, interval=5):
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        data = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30).json().get("data") or {}
        status = data.get("status")
        if status == "success":
            return data["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"task failed: {data.get('error')}")
        time.sleep(interval)
    raise TimeoutError(task_id)

url = wait(submit())
mp4 = requests.get(url, timeout=120).content   # 즉시 다운로드 — 출력 URL은 만료됩니다
open("ad.mp4", "wb").write(mp4)

Q3-ad 렌더링은 보통 1~2분 안에 완료되므로 5초 폴링 간격이면 충분합니다. 출력 URL은 임시이며(expireAt 포함), 작업이 성공하면 페이지에 핫링크하지 말고 즉시 바이트를 다운로드하세요.

프로덕션 환경 패턴

폴링 대신 콜백을 사용하세요. 서버 시나리오에서는 최상위 callback을 걸어 폴링 루프를 유지할 필요가 없게 하세요.

{
  "model": "vidu-q3-ad/reference-to-video",
  "input": { "prompt": "...", "reference_image_urls": ["..."], "duration": 5 },
  "callback": { "url": "https://your-app.com/hooks/hiapi", "when": "final" }
}

when은 "final"만 지원합니다. 작업이 종료 상태에 들어갈 때 훅이 한 번 트리거되며, 요청 본문은 GET /v1/tasks/{taskId}가 반환하는 페이로드와 동일합니다. 훅이 재시도될 수 있으므로 taskId로 중복 제거하고, 전달이 유실될 경우를 대비해 느린 폴링을 폴백으로 유지하세요.

HTTP 상태 코드가 아니라 응답 본문을 기준으로 분기하세요. 렌더링 실패도 HTTP 200을 반환합니다. 실패 정보는 data.status == "fail"에 있고 상세 내용은 data.error에 있습니다. 요청 수준 거부 (필드 오류, 키 누락, 미인증)만 4xx를 사용하며 {"code":400,"error_code":"INVALID_REQUEST","message":"...","data":null}을 반환합니다.

멱등성. 제출할 때마다 새로운 과금 작업이 생성되므로 taskId를 받는 즉시 저장하고, 재시도 시 해당 ID로 다시 폴링하세요. 단일 폴링 요청이 타임아웃되었다고 절대 다시 제출하지 마세요.

내가 검증한 것

유효하지 않은 값으로 라이브 엔드포인트를 프로빙했으며, 이런 값들은 검증 단계에서 무료로 거부됩니다. 작업이 생성되지 않고 과금도 되지 않습니다 (유효하지 않은 값은 렌더링이 시작되기 전에 실패하므로 필드 누락보다 안전합니다). 실제 응답이 곧 스키마입니다.

  • 거의 빈 요청 본문 → reference_image_urls: missing required field ...; duration: missing required field .... 따라서 prompt, reference_image_urls, duration은 모두 필수입니다.
  • duration: 99999 → maximum: got 99,999, want 15; duration: 1 → minimum: got 1, want 3; duration: 4.5 → got number, want integer. Duration은 3–15의 정수입니다.
  • reference_image_urls에 8개 항목 전달 → maxItems: got 8, want 7. 상한은 7입니다.
  • size: "9000p" → value must be one of '1280*720', '1280*960', '1280*1280', '960*1280', '720*1280', '1920*1080', '1920*1440', '1808*1808', '1440*1920', '1080*1920'.
  • aspect_ratio와 resolution → 둘 다 additional properties ... not allowed를 반환합니다. q3-ad의 필드가 아니며 size를 사용해야 합니다.
  • reference_audio_urls를 올바른 형식의 배열로 전달 → additional properties 'reference_audio_urls' not allowed. (배열이 아닌 형식으로 전달하면 먼저 별도의 미디어 검사인 "must be an array"가 트리거되어 오해를 유발합니다. 이 필드는 확실히 스키마에 없습니다.) 이 티어에는 음성 참조 입력이 없으며 오디오는 네이티브로 생성됩니다.

이 문서는 통합 참고 자료이므로 화질에 대한 주장은 포함하지 않습니다. 이 글을 위해 유료 렌더링을 실행하지 않았습니다. 성공한 output[0].url이 어떤 모습인지는 아래 모델 페이지에 해당 엔드포인트의 예시가 호스팅되어 있습니다. 실제 오디오 트랙이 포함된 MP4입니다.

관련 가이드

자주 묻는 질문

클립을 세로 또는 가로로 만들려면 어떻게 하나요? aspect_ratio가 아니라 size로 설정합니다. 세로는 720*1280 또는 1080*1920, 가로는 1280*720 또는 1920*1080을 사용하세요.

나레이션이나 음성 참조를 제공할 수 있나요? 이 티어에서는 불가능합니다. reference_audio_urls는 거부됩니다. Q3-ad는 네이티브 오디오를 자체 생성합니다. 참조 클립으로 오디오를 구동해야 한다면 Vidu Q4의 reference-to-video 티어를 사용하세요.

제품 이미지를 몇 장까지 보낼 수 있나요? 1~7장이며 reference_image_urls에 넣고 프롬프트에서 번호로 참조하세요 ("참조 이미지 2의 병").

작업이 200을 반환했는데 비디오가 없습니다. 왜 그런가요? data.status를 확인하세요. "fail"도 HTTP 200을 반환하며 원인은 data.error에 있습니다. 형식이 잘못된 요청만 4xx를 받습니다.

비용은 얼마인가요? 출력 초 수를 기준으로 과금되며, size 등급 (720급 vs 1080급)이 초당 단가를 결정합니다. 최소 3초 클립입니다. 현재 요금은 가격을 참고하세요.

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

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

API 문서 보기