요약: AI API로 동영상을 생성하려면 텍스트 프롬프트를 비디오 모델 엔드포인트에 POST하고, 작업 ID를 받은 다음, 완성된 MP4가 준비될 때까지 해당 작업을 폴링하면 됩니다. 대략 파이썬 10줄입니다. GPTProto의 통합 API는 하나의 키와 하나의 잔액으로 5개의 비디오 모델을 제공합니다: Seedance 2.0, ViduQ3-pro, Kling v3.0 std, Hailuo 2.3 Pro, Veo 3.1. URL의 문자열 하나만 변경하면 모델을 전환할 수 있습니다. 인증, 요청 형식, 폴링은 동일하게 유지됩니다. 요금은 선불 종량제이며, 동영상 1초당 약 $0.04부터 시작합니다.
서로 다른 5개 비디오 모델을 호출하려면 예전에는 계정 5개, SDK 5개, 결제 대시보드 5개가 필요했습니다. ByteDance의 Seedance 2.0을 원하시나요? BytePlus(Volcano Engine) 계정과 중국 외 대부분의 사람이 오후 중에 통과할 수 없는 신원 확인 절차가 필요합니다. Google의 Veo를 원하시나요? 다른 콘솔, 다른 키가 필요합니다. 같은 프롬프트로 두 모델을 A/B 테스트하고 싶으신가요? 그렇다면 공유되는 것이 없는 두 개의 통합을 유지해야 합니다.
이 가이드에서는 그런 과정을 건너뜁니다. 파이썬 약 10줄로 첫 text-to-video API 호출을 만들고, 완성된 MP4를 폴링한 다음, URL의 문자열 하나만 변경해 나머지 4개 모델에 도달할 수 있습니다. 동일한 키, 동일한 코드, 동일한 잔액입니다.
공개: 저는 GPTProto를 위한 통합 가이드를 작성하므로, 어떤 엔드포인트를 사용하느냐에 따라 이해관계가 있습니다. 그래도 수치는 정직하게 유지했습니다. 아래에서 직접 호출하는 것보다 우리를 호출하는 것이 더 비싸 비용이 드는 모델도 포함합니다. 그런 경우에는 분명히 말씀드리겠습니다.
AI 동영상 생성 API란 실제로 무엇인가
노코드 버튼이 아닙니다. 비동기 작업입니다. 프롬프트를 POST하면 API가 ID를 반환하고, 모델이 30초에서 수 분 동안 렌더링하며, 비디오가 준비될 때까지 두 번째 엔드포인트를 폴링합니다. 이 렌더링 지연이 2단계 설계의 이유입니다. 비디오는 HTTP 연결을 계속 열어두기엔 너무 오래 걸리므로, 파일 대신 작업 티켓을 받는 것입니다.
구축할 거의 모든 것을 포괄하는 세 가지 요청 유형이 있습니다:
- text-to-video — 프롬프트가 클립이 됩니다.
- image-to-video — 정지 프레임이 애니메이션으로 움직입니다.
- reference-to-video — 하나 이상의 참조 이미지를 사용해 캐릭터나 객체가 여러 컷에서 일관되게 유지됩니다.
아래 모든 내용은 동일한 기본 URL https://gptproto.com/api/v3과 동일한 헤더를 사용합니다. 키를 받아 첫 호출을 해보겠습니다.
API 키 받기
gptproto.com에 가입하고, 대시보드의 API Keys 섹션을 열어 키를 생성하세요. 키는 sk-... 형식입니다. 여기에는 상시 무료 티어가 없습니다. 요금은 선불 종량제이므로 잔액을 충전하면 첫 요청부터 모든 호출이 그 잔액에서 차감됩니다. 테스트에는 몇 달러만 예산하세요. 짧은 클립 몇 개는 그보다 더 들지 않습니다.
하나의 의존성만 설치하세요:
pip install requests
첫 호출 전에 제대로 알고 가야 할 한 가지가 있습니다. 많은 사람이 실수하는 부분입니다. 네이티브 /api/v3/ 표면에서 Authorization 헤더는 원시 키, Bearer 접두사 없음입니다. GPT Proto는 또한 OpenAI 호환 /v1/ 표면을 제공하며, 이쪽은 Bearer를 사용합니다. 이 둘을 혼동하는 것이 제가 보는 가장 흔한 401 원인입니다. 이 튜토리얼 전체에서는 네이티브 표면을 사용하므로 키를 원시 형식으로 넣습니다.
첫 번째 호출: Seedance 2.0, text-to-video
Seedance 2.0은 ByteDance의 2세대 비디오 모델입니다. 최대 1080p, 4~15초 클립을 기본 동기화 오디오와 함께 렌더링하며, 카메라 컷이 있어도 피사체가 일관되게 유지되는 멀티샷 장면에 적합합니다. 다음은 완전한 text-to-video 제출 코드입니다:
import requests
import time
API_KEY = "sk-your-key-here" # raw, no "Bearer" prefix
BASE = "https://gptproto.com/api/v3"
headers = {
"Authorization": API_KEY,
"Content-Type": "application/json",
}
def submit_seedance(prompt):
url = f"{BASE}/bytedance/dreamina-seedance-2-0-260128/text-to-video"
payload = {
"prompt": prompt,
"duration": 5, # 4-15 seconds
"aspect_ratio": "16:9",
"resolution": "1080p",
"generate_audio": True,
"camera_fixed": False,
"seed": -1, # -1 = random
}
resp = requests.post(url, headers=headers, json=payload)
resp.raise_for_status()
return resp.json()["data"]["id"]
prompt = (
"A lighthouse keeper climbs a narrow spiral staircase at dawn. "
"Cut to a wide shot of the lamp room as the light sweeps across "
"grey water. Waves crash below. Ambient wind and distant gulls."
)
job_id = submit_seedance(prompt)
print("submitted:", job_id)
와이어 형식을 직접 보고 싶다면 동일한 요청을 cURL로도 작성할 수 있습니다:
curl -X POST "https://gptproto.com/api/v3/bytedance/dreamina-seedance-2-0-260128/text-to-video" \
-H "Authorization: sk-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A lighthouse keeper climbs a spiral staircase at dawn, then the lamp sweeps across grey water.",
"duration": 5,
"aspect_ratio": "16:9",
"resolution": "1080p",
"generate_audio": true,
"camera_fixed": false,
"seed": -1
}'
응답에는 비디오가 포함되지 않습니다. 작업(Job) ID가 포함됩니다:
{
"data": {
"id": "cgt-20260709xxxxxx-abc",
"status": "created",
"outputs": [],
"urls": { "get": "https://gptproto.com/api/v3/predictions/cgt-20260709xxxxxx-abc/result" }
},
"message": "success",
"code": 200
}
data.id가 사용자의 작업 티켓입니다. data.urls.get은 ID가 이미 포함된 준비된 폴링 URL입니다. 요약하면, 작업을 제출하고 ID를 받았지만 아직 렌더링된 것은 없다는 뜻입니다.
결과 폴링
이제 status가 completed로 바뀔 때까지 결과 엔드포인트를 호출한 다음, outputs에서 비디오 URL을 읽어옵니다. 플랫폼의 모든 모델은 동일한 폴링 엔드포인트와 동일한 응답 구조를 사용합니다. 이것이 나중에 "문자열 하나만 바꾸는" 트릭이 작동하는 이유입니다:
def wait_for_video(job_id, every=5, timeout=600):
url = f"{BASE}/predictions/{job_id}/result"
waited = 0
while waited < timeout:
resp = requests.get(url, headers=headers)
resp.raise_for_status()
data = resp.json()["data"]
status = data["status"]
if status == "completed":
return data["outputs"][0] # the MP4 URL
if data.get("error"):
raise RuntimeError(data["error"])
print(f" {status}... {waited}s")
time.sleep(every)
waited += every
raise TimeoutError(f"timed out after {timeout}s (last status: {status})")
video_url = wait_for_video(job_id)
print("done:", video_url)
이것이 완전히 동작하는 생성입니다. 함수 2개, 프롬프트 1개, MP4 1개입니다. 5초 클립은 보통 1~2분 안에 완료되지만, 오디오가 포함된 15초 1080p 렌더링은 더 오래 걸릴 수 있습니다. 몇 초 간격으로 폴링하되 너무 자주 호출하지는 마세요.
루프에 대한 참고 사항: error가 발생하면 예외를 raise하고, completed도 아니고 오류도 아닌 상태는 모두 "계속 대기"로 처리합니다. 의도적입니다. 모델마다 중간 상태를 다르게 보고하므로, 변경될 수 있는 상태 목록을 하드코딩하는 대신 명확한 실패가 아닌 한 계속 기다리는 것이 안전합니다.
문자열 하나만 바꾸면 엔진이 바뀐다: ViduQ3-pro
이것이 핵심입니다. Seedance 대신 ViduQ3-pro에서 동일한 프롬프트를 렌더링하려면 경로만 변경하면 됩니다. 키, 헤더, wait_for_video()는 그대로입니다:
def submit_vidu(prompt):
url = f"{BASE}/vidu/viduq3-pro/text-to-video"
payload = {
"prompt": prompt,
"duration": 5, # ViduQ3 goes up to 16s
"aspect_ratio": "16:9",
"resolution": "1080p",
"audio": True, # note: ViduQ3 uses `audio`, not `generate_audio`
"seed": -1,
}
resp = requests.post(url, headers=headers, json=payload)
resp.raise_for_status()
return resp.json()["data"]["id"]
job_id = submit_vidu(prompt)
video_url = wait_for_video(job_id) # same poller, unchanged
ViduQ3-pro는 클립 길이를 16초까지 늘려줍니다. Seedance의 실용 범위의 두 배이며, 여기 모델 중 초당 가격이 가장 저렴합니다. 파라미터 이름은 모델마다 조금씩 다릅니다(ViduQ3는 사운드를 audio로 제어하고, Seedance는 generate_audio를 사용합니다). 정확한 필드 세트는 모델 페이지를 확인하세요. 하지만 요청/제출/폴링 흐름은 변하지 않습니다.
캐릭터 일관성 유지. 두 주력 모델 모두 text-to-video 이상의 기능을 제공합니다. ViduQ3에 /vidu/viduq3-pro/image-to-video 경로와 image 필드를 지정해 정지 이미지를 애니메이션으로 만들거나, Seedance의 reference-to-video 모드에서 참조 이미지를 사용해 같은 얼굴이 여러 컷에서 유지되도록 할 수 있습니다. 이는 동일한 제출-폴링 흐름입니다. 새 API를 배우는 것이 아니라 이미지 입력만 추가하는 것입니다. 프로덕션에 연결하기 전에 각 모델 페이지에서 참조 필드 이름을 확인하세요.
어떤 모델을 호출해야 할까?
다섯 가지 모델, 하나의 키. 더 큰 숫자가 항상 이기는 계층 구조가 아니라, 각각 다른 작업을 위한 모델입니다. 클립의 요구사항에 따라 선택하세요:
| 모델 |
경로 ({provider}/{model}) |
기본 오디오 |
최대 길이 |
가격 |
이런 경우에 사용하세요 |
| Seedance 2.0 |
bytedance/dreamina-seedance-2-0-260128 |
예 |
~15초 |
$0.2957/회부터 |
동기화 사운드가 있는 멀티샷 장면 |
| ViduQ3-pro |
vidu/viduq3-pro |
예 |
16초 |
$0.04/초부터 |
더 긴 클립, 가장 저렴한 가격 |
| Kling v3.0 std |
kling/kling-v3.0-std |
예 |
~10초 |
$0.2016/회부터 |
저렴하고 믿을 수 있는 image-to-video |
| Hailuo 2.3 Pro |
minimax/hailuo-2.3-pro |
아니오 |
~10초 |
$0.441/회 |
사운드를 직접 추가할 때 깨끗한 1080p |
| Veo 3.1 |
google/veo3.1 |
예 |
— |
$0.5/회부터 |
4K 출력이 필요할 때 |
선택하기 전에 짚어둘 두 가지가 있습니다. Hailuo 2.3 Pro는 무음 비디오를 반환합니다. 화질은 좋지만 후반 작업에서 사운드를 입혀야 합니다. Veo 3.1은 모든 출력에 끌 수 없는 SynthID 워터마크를 내장합니다. 출처 표시가 박히는 것을 원하지 않는 클라이언트에게 전달하는 경우 중요합니다.
플랫폼이 이 모든 것을 하나의 제출/폴링 계약으로 정규화하기 때문에, 모델 간 전환은 재작성이 아니라 딕셔너리 조회일 뿐입니다:
MODELS = {
"seedance": "bytedance/dreamina-seedance-2-0-260128",
"vidu": "vidu/viduq3-pro",
"kling": "kling/kling-v3.0-std",
"hailuo": "minimax/hailuo-2.3-pro",
"veo": "google/veo3.1",
}
def submit(model_key, scene, payload):
url = f"{BASE}/{MODELS[model_key]}/{scene}"
resp = requests.post(url, headers=headers, json=payload)
resp.raise_for_status()
return resp.json()["data"]["id"]
# same wait_for_video() retrieves any of them
job_id = submit("kling", "image-to-video", {"prompt": prompt, "image": image_url})
페이로드는 모델마다 다릅니다. 그것은 사용자가 조정하는 부분입니다. 하지만 검색, 인증, 결과 가져오기는 달라지지 않습니다.
실제 비용은 얼마인가
비디오 가격은 초당 또는 건당으로 책정되며, 해상도, 길이, 오디오 생성 여부에 따라 크게 달라집니다. 모델 페이지의 대표 숫자는 최저 기준이지 예상치가 아닙니다. 실제 예로, 오디오가 포함된 Seedance 720p / 16:9 / 5초 클립은 약 $0.605입니다. 기준 $0.2957보다 훨씬 높은데, 모든 비용 요소를 한 번에 올렸기 때문입니다. 실제 설정은 스티커 가격이 아니라 대시보드 견적으로 책정하세요.
각 벤더를 직접 호출하는 것과 비교한 정직한 비교는 다음과 같습니다:
- ViduQ3-pro — $0.04/초부터, 시장 기준 약 $0.05/초보다 약 20% 저렴합니다.
- Kling v3.0 std — $0.2016/회부터, 약 $0.252 기준보다 약 20% 저렴합니다.
- Hailuo 2.3 Pro — MiniMax의 약 $0.49 대비 $0.441/회로 약 10% 저렴합니다.
- Seedance 2.0 — $0.2957/회부터, ByteDance의 자체 Dreamina에서 동일한 클립을 직접 렌더링하는 것보다 약 10% 이상비쌉니다. 솔직히 그렇지 않다고 말하지 않겠습니다. API를 통해 호출하는 이유는 더 낮은 가격이 아니라 안정적인 프로그래밍 방식 액세스, 하나의 잔액, BytePlus 신원 확인이 필요 없다는 점입니다. Seedance에 대해 비용만 중요하다면 직접 호출하는 것이 더 저렴합니다.
- Veo 3.1 — $0.5/회부터. 페이지에 명확한 시장 기준이 없으므로, 할인이 아닌 편의성 옵션으로 생각하세요.
무료 티어도 월간 구독도 없습니다. 첫 요청부터 호출당 비용을 지불합니다. 특정 모델의 가격은 모델 카탈로그 에서 현재 초당 및 해상도별 요금표를 확인할 수 있습니다.
오류 및 주의사항
무엇이 잘못되는지에 대한 간단한 안내입니다:
- 401 Unauthorized — 거의 항상
Bearer 혼동입니다. 네이티브 /api/v3/ 표면은 원시 키를 요구합니다.
- 403 Forbidden — 대개 권한 문제가 아니라 잔액이 비어 있는 경우입니다. 충전하세요.
- 429 — 요청 한도에 도달했습니다. 잠시 멈췄다가 재시도하세요.
- 콘텐츠 메시지가 포함된 400 — 프롬프트가 모더레이션에 걸렸습니다. 응답에는
has_nsfw_contents 플래그도 포함되어 있으므로 파이프라인에서 확인할 가치가 있습니다.
- 폴링이 완료되지 않음 — 오래 걸리는 렌더링이 존재합니다. 그래서
wait_for_video()는 무한 루프 대신 타임아웃이 있는 것입니다.
- 잘못된 오디오 파라미터 —
generate_audio(Seedance)와 audio(ViduQ3)를 혼동하는 경우입니다. 잘못된 값을 보내면 오류가 나지 않고 조용히 무시되는데, 그게 더 나쁩니다. 모델별 필드 이름을 확인하세요.
여기서 시작하세요
가장 빠른 방법: 키를 만들고 위의 Seedance와 ViduQ3 스니펫을 실행한 다음, 모델 문자열만 바꿔 나머지를 시도해 보세요. 모델 선택에 필요한 모든 것(현재 가격, 지원 모드, 해상도 표)은 카탈로그의 각 모델 페이지에 있습니다. 하나의 키, 하나의 잔액, 다섯 개의 비디오 엔진.