HiAPI
블로그

튜토리얼

Ray 3.2 텍스트 투 비디오 API 사용 방법: curl, Python, 그리고 바로 실행 가능한 요청

Oct 20, 2026
Ray 3.2 텍스트 투 비디오 API 사용 방법: curl, Python, 그리고 바로 실행 가능한 요청

Ray 3.2는 hiapi 모델 카탈로그에 있는 텍스트 투 비디오 모델로, 다른 모든 비디오 모델과 마찬가지로 통합된 비동기 작업 API를 통해 호출됩니다. 모델 id는 ray-3.2/text-to-video이며, POST /v1/tasks로 제출합니다. 일부 비디오 모델은 조정 가능한 항목이 프롬프트 하나뿐이지만, Ray 3.2는 다릅니다. 실제로 사용 가능한 세 가지 출력 제어 항목인 duration, resolution, aspect_ratio를 제공하며, 각 항목은 서버 측에서 엄격하게 검증됩니다.

이 가이드는 한 번에 성공하는 요청을 보낼 수 있게 해줍니다. 정확한 입력 스키마(2026-10-19 기준 라이브 API와 대조 검증 완료), 그대로 복사해 붙여넣을 수 있는 curl 호출, 완전한 Python 제출/폴링/다운로드 스크립트, 그리고 프로덕션 환경 세부 사항—콜백, 멱등 재시도, 그리고 실제로 마주하게 될 오류 응답을 다룹니다.

무엇을 만들고 무엇을 준비해야 하나요

목표: 텍스트 프롬프트를 제출하고, 작업을 폴링한 뒤, 무음 .mp4 클립(5초 또는 10초)을 다운로드합니다.

사전 요구 사항:

  • hiapi API 키—콘솔에서 발급받으세요. 키는 sk-... 형태이며 Authorization: Bearer 요청 헤더에 넣습니다. 작업 API가 처음이라면 빠른 시작부터 시작하세요.
  • 아무 HTTP 클라이언트나 사용 가능합니다. curl과 Python(requests)을 보여드립니다.

Ray 3.2의 출력은 클립 단위로 과금되며 가격은 선택에 따라 크게 올라갑니다—현재 요율은 가격 페이지를 참고하세요. 프롬프트를 반복 실험할 때는 540p / 5초로 시작하세요. 1080p 10초 클립은 예산 규모의 이미지 렌더링보다 몇 배 더 비쌀 수 있으므로, 개발 루프를 항상 최고 설정으로 돌리지 마세요.

정확한 입력 스키마(필수 필드 하나, 엄격한 열거형 세 개)

모든 내용은 하나의 input 객체에 들어갑니다. 라이브 API와 필드별로 대조 검증했습니다:

필드 타입 필수 허용 값 기본값
prompt string 예 장면 설명, 최대 6000자 —
duration integer 아니오 5 또는 10 5
resolution string 아니오 540p, 720p, 1080p 540p
aspect_ratio string 아니오 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 16:9

코드를 작성하기 전에 명심해야 할 세 가지가 있습니다:

  1. duration은 정수이지 문자열이 아닙니다. 숫자 그대로 보내세요—"duration": 5. 이는 다른 일부 작업 API 비디오 모델과 반대입니다(예: hailuo-2.3은 "duration": "6"을 문자열로 요구합니다). 요청 본문을 한 모델에서 다른 모델로 옮길 때는 이 필드를 다시 확인하세요. 가장 흔한 모델 간 오류입니다.
  2. 열거형 값은 검증되며 잘리지 않습니다. 범위를 벗어난 값은 조용히 반올림되지 않고 400으로 거부됩니다. 2k도, 480p도, 2:1도 없습니다.
  3. prompt_optimizer, seed, negative_prompt는 없습니다. 구도는 전적으로 aspect_ratio와 프롬프트로 제어합니다. 스키마가 인식하지 못하는 필드를 보내면 400을 받을 것으로 예상하세요—/v1/tasks의 입력 스키마는 모델마다 다르므로, 다른 곳에서 유효했던 키가 그대로 통할 것이라고 가정하지 마세요.

검증이 실제로 반환하는 것

다음은 라이브 엔드포인트의 실제 응답입니다(의도적으로 유효하지 않은 값을 제출하며, 작업이 생성되지 않고 과금되지 않음):

// POST with "resolution": "2k"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
 "message":"invalid input: resolution: value must be one of '540p', '720p', '1080p'"}

// POST with "duration": 7
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
 "message":"invalid input: duration: value must be one of 5, 10"}

// POST with "aspect_ratio": "2:1"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
 "message":"invalid input: aspect_ratio: value must be one of '16:9', '9:16', '1:1', '4:3', '3:4', '21:9'"}

message는 정확한 필드와 정확한 허용 집합을 알려줍니다—열거형 값을 잊었다면 API가 알려주는 셈입니다. duration의 5, 10에는 따옴표가 없고(숫자), resolution의 '540p'는 따옴표가 붙은 문자열이라는 점에 주목하세요. 이 따옴표 차이가 어느 필드가 정수인지 알려주는 힌트입니다.

최소 실행 예제: curl

작업 생성:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ray-3.2/text-to-video",
    "input": {
      "prompt": "비 내리는 밤, 한 스트리트 댄서가 네온 불빛 아래에서 회전하고, 물웅덩이에 분홍색과 파란색 불빛이 비치며, 그녀의 재킷이 회전에 맞춰 펄럭이고, 카메라가 낮은 앵글로 그녀를 둘러싸며, 영화 같은 느낌",
      "duration": 5,
      "resolution": "540p",
      "aspect_ratio": "9:16"
    }
  }'

생성 응답에는 작업 id가 포함됩니다(일부 생략):

{ "data": { "taskId": "task_01k..." } }

종료 상태가 될 때까지 폴링합니다:

curl -s https://api.hiapi.ai/v1/tasks/task_01k... \
  -H "Authorization: Bearer sk-YOUR_KEY"

작업이 실행되는 동안 data.status는 진행 중 상태를 보고합니다. 두 가지 종료 상태는 success와 fail입니다. 성공 시(일부 생략):

{
  "data": {
    "taskId": "task_01k...",
    "status": "success",
    "output": [ { "url": "https://.../clip.mp4" } ]
  }
}

data.output[0].url을 즉시 다운로드하세요. 출력 URL은 서명되어 있으며 만료됩니다—작업 URL을 직접 핫링크하지 말고 바이트를 자체 스토리지에 저장하세요. Ray 3.2는 무음 MP4(오디오 트랙 없음)를 반환하므로, 결코 오지 않을 오디오 스트림을 기다리지 마세요.

완전한 Python 스크립트(제출 → 폴링 → 다운로드)

import time
import requests

API_BASE = "https://api.hiapi.ai/v1"
API_KEY = "sk-YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}


def create_task(prompt: str, duration: int = 5,
                resolution: str = "540p", aspect_ratio: str = "9:16") -> str:
    resp = requests.post(
        f"{API_BASE}/tasks",
        headers=HEADERS,
        json={
            "model": "ray-3.2/text-to-video",
            "input": {
                "prompt": prompt,
                "duration": duration,          # 5 or 10 — an INTEGER, not a string
                "resolution": resolution,      # "540p" | "720p" | "1080p"
                "aspect_ratio": aspect_ratio,  # "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"
            },
        },
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()["data"]["taskId"]


def wait_task(task_id: str, timeout_s: int = 900, poll_interval: int = 5) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        resp = requests.get(f"{API_BASE}/tasks/{task_id}", headers=HEADERS, timeout=30)
        resp.raise_for_status()
        task = resp.json()["data"]
        if task["status"] == "success":
            return task
        if task["status"] == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
        time.sleep(poll_interval)  # any non-terminal status = still running
    raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")


task_id = create_task(
    "종이배 한 척이 빗물로 가득 찬 배수로를 따라 떠내려가고, 물방울이 수면에 파문을 일으키며, "
    "가을 낙엽이 소용돌이치며 지나가고, 수면에 낮게 붙은 로우 앵글로 촬영, 부드러운 흐린 날의 빛"
)
print("task created:", task_id)

task = wait_task(task_id)
video_url = task["output"][0]["url"]

# Output URLs expire — download right away and store the bytes yourself.
video = requests.get(video_url, timeout=120).content
with open("ray32-clip.mp4", "wb") as f:
    f.write(video)
print(f"saved ray32-clip.mp4 ({len(video) / 1e6:.1f} MB)")

pip install requests로 의존성을 설치하고, 키를 바꿔 넣으면 작업 완료 시 디스크에 .mp4가 생깁니다. 비디오 작업은 몇 초가 아니라 몇 분이 걸립니다—폴링 루프에 넉넉한 데드라인을 두세요(위에서는 15분). 빠르게 반환될 것이라고 가정하지 마세요.

프로덕션 환경 고려 사항: 콜백, 멱등성, 오류

폴링보다 콜백 선호

스크립트 이외의 용도라면 폴링 대신 작업 생성 시 웹훅을 등록하세요:

{
  "model": "ray-3.2/text-to-video",
  "input": { "prompt": "...", "duration": 10, "resolution": "720p" },
  "callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}

"when": "final"을 사용하면 hiapi가 작업이 종료 상태에 들어갈 때 엔드포인트를 한 번 호출합니다—폴링 트래픽이 없고, 두 간격 사이에 완료 알림을 놓치지도 않습니다. 이후 핸들러에서 GET /v1/tasks/<id>를 실행하거나(또는 전달된 응답 본문을 읽거나) output[0].url을 가져옵니다. HTTPS 엔드포인트를 노출할 수 없는 CLI와 노트북에서는 폴링도 여전히 괜찮습니다.

재시도를 멱등하게 유지

생성 호출이 반환되는 즉시 taskId를 영속화하세요. 프로세스가 생성 중간에 충돌하더라도 저장된 id를 폴링하여 복구하세요—작업을 다시 생성하지 마세요. 그렇지 않으면 두 번째 렌더링에 비용을 지불하게 됩니다. 원래 생성 요청 자체가 작업 id를 반환하기 전에 실패한 경우에만 다시 생성하세요. Ray 3.2는 클립 단위로 과금되고 고해상도 클립은 저렴하지 않으므로, 중복 생성은 단순한 시간 낭비가 아니라 실질적인 비용 오류입니다.

실제로 마주하게 될 오류

아래 각 행은 검증된 라이브 응답 형태입니다:

증상 응답 해결 방법
키 누락/잘못됨 401, 중첩 {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} Authorization: Bearer sk-... 헤더와 키에 접근 권한이 있는지 확인하세요. 지원 문의 시 request_id를 제공하세요.
열거형 값 오류 400 INVALID_REQUEST, 평면 {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: <field>: value must be one of ..."} message에 지정된 필드를 읽으세요. 정확한 허용 집합을 나열합니다.
duration을 문자열로 전송 400 INVALID_REQUEST "5"가 아닌 숫자 그대로의 정수 5 또는 10을 보내세요.
알 수 없는 모델 id 400, error_code: "MODEL_UNAVAILABLE", "model not available via /v1/tasks" 반드시 ray-3.2/text-to-video를 사용하세요—모델 페이지에서 정식 id를 확인하세요.
폴링 시 작업 id 오류 404, 평면 {"code":404,"data":null,"message":"task not found"} (참고: 404에는 error_code가 없음) id가 틀렸거나, 다른 계정의 키로 조회한 경우입니다.
폴링 시 status: "fail" 작업 종료 상태, 상세 정보는 data.error data.error.code / data.error.message를 읽으세요. 실패한 작업은 환불됩니다. 콘텐츠 정책 플래그와 업스트림 용량 문제가 여기서 드러나며, 콘텐츠 플래그의 경우 프롬프트를 수정하여 재시도하세요.

관련 리소스

자주 묻는 질문

모델 id는 무엇이고 어떤 엔드포인트를 호출해야 하나요? ray-3.2/text-to-video이며, 최상위 model로 POST https://api.hiapi.ai/v1/tasks에 제출하고 파라미터는 input 아래에 둡니다. 비동기이므로 taskId를 받은 뒤 GET /v1/tasks/<id>로 폴링하거나 콜백을 등록합니다.

duration은 초 단위인가요, 왜 "5"는 실패하나요? 클립은 5초 또는 10초이며, 이 필드는 정수입니다. 5 또는 10을 보내세요. 따옴표로 감싼 문자열이나 7 같은 다른 숫자는 400 INVALID_REQUEST: duration: value must be one of 5, 10으로 실패합니다.

해상도와 가로세로 비율을 설정할 수 있나요? 예—이것이 Ray 3.2가 프롬프트만 지원하는 비디오 모델과 다른 점입니다. resolution은 540p, 720p, 1080p 중 하나이고, aspect_ratio는 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 중 하나입니다. 둘 다 선택 사항이며(기본값 540p, 16:9), 범위를 벗어난 값은 400으로 거부됩니다.

클립 하나에 얼마인가요? Ray 3.2는 클립 단위로 과금되며 해상도가 가장 큰 변수입니다—같은 길이라면 1080p 클립은 540p의 몇 배 비용이고, 10초 클립은 5초 클립의 약 세 배 비용입니다. 요율은 변동되므로 숫자를 하드코딩하지 말고 가격 페이지를 확인하며, 540p/5초로 프로토타입하세요.

클립에 오디오가 있나요? 없습니다—Ray 3.2 텍스트 투 비디오는 무음 MP4를 반환합니다. 소리가 필요하면 후반 작업에서 추가하거나 별도 오디오 모델을 사용하세요.

Ray 3.2는 이미지 투 비디오를 지원하나요? 예, 같은 작업 API에서 별도 모델 id인 ray-3.2/image-to-video로 지원합니다. 입력 스키마가 다르므로(참조 이미지를 받음) 이 요청 본문을 재사용하기 전에 먼저 확인하세요—이미지 투 비디오 모델 페이지를 참고하세요.

생성이 느리거나 멈춘 것처럼 보입니다. 무엇이 정상인가요? 비디오 작업은 몇 분간 실행됩니다. 폴링 루프에서 종료 상태가 아닌 data.status를 유지하며 기다리세요—10–15분의 데드라인을 두거나, "when": "final"이 있는 callback을 사용하여 간격을 추측하는 대신 hiapi가 종료 상태 시 알려주도록 하세요.

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

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

API 문서 보기