spicyapi문서
가이드
본문

이미지→영상 튜토리얼

내 컴퓨터에 있는 이미지 한 장에서 시작해, 내려받은 영상 파일을 손에 넣기까지 안내합니다. 모든 단계를 CLI, TypeScript SDK, 일반 HTTP 세 가지 방법으로 보여 줍니다.

이 튜토리얼에서는 내 컴퓨터에 있는 이미지 한 장으로 짧은 영상 클립을 만들고, 내려받아 보관하는 데까지 진행합니다. 모델 고르기, 이미지 업로드, 가격 확인, 생성 시작, 완료 기다리기, 결과 내려받기, 문제가 생겼을 때 대처하기까지 전 과정을 순서대로 모두 다루므로, 레퍼런스 페이지를 여기저기 읽으며 직접 이어 붙일 필요가 없습니다.

모든 단계에서 같은 일을 세 가지 방법으로 보여 줍니다. 하나를 골라 끝까지 그 방법으로 진행하세요.

방법이럴 때 고르세요필요한 것
CLI코드를 짜지 않고 명령만 입력하고 싶을 때Node.js 22.13 이상
TypeScript SDKNode.js 프로그램을 만들고 있고, 그 프로그램이 어떤 호출을 하는지 보고 싶을 때Node.js 22.13 이상
HTTP (curl)API를 가공 없이 그대로 보고 싶을 때. 예를 들어 나중에 다른 프로그래밍 언어에서 쓰려는 경우curl과 jq가 있는 bash 터미널(macOS, Linux 또는 Windows의 WSL)

AI 어시스턴트에게 맡기고 싶다면 AI 어시스턴트로 진행하기를 보세요.

만들게 될 결과물

  • 결과: 짧은 영상 파일(보통 MP4)입니다. 내 이미지에서 시작해, 내가 쓴 문장대로 움직입니다.
  • 걸리는 시간: 처음에는 20분 정도 잡으세요. 대부분은 읽는 시간입니다. 생성 자체는 보통 몇 분이면 끝나지만, 모델과 설정에 따라 더 오래 걸리기도 합니다.
  • 실행되는 곳: SpicyAPI입니다. 내 컴퓨터는 이미지와 지시 사항을 보내고, 완성된 파일을 내려받기만 합니다.

비용, 그리고 돈을 내기 전에 확인하는 법

가격은 미국 달러입니다. 고른 모델과 영상 길이·해상도 같은 설정에 따라 달라지므로 이 페이지에는 금액을 적지 않습니다. 가격은 세 곳에서 볼 수 있으며, 어느 것도 비용이 들지 않습니다.

  1. 실시간 카탈로그(1단계)는 내 계정으로 쓸 수 있는 모든 모델을 내 계정에 적용되는 가격과 함께 보여 줍니다. 영상은 보통 출력 1초당(per_second) 가격이 매겨집니다. 한 모델에 가격이 여러 개 있다면 각각이 해상도 같은 설정 하나에 해당합니다.
  2. 견적(3단계)은 내가 보낼 바로 그 요청의 정확한 가격을 알려 줍니다. 아무것도 시작하지 않고, 금액을 예약하지도 않습니다.
  3. 확인 절차: CLI는 가격을 한 번 더 보여 주고, 내가 y를 입력할 때까지 아무것도 시작하지 않습니다.

돈은 이렇게 움직입니다.

  • 비용이 드는 것은 4단계뿐이고, 실패한 작업을 다시 실행할 때도 비용이 듭니다. 모델 목록 보기, 업로드, 견적, 기다리기, 내려받기는 무료입니다.
  • 생성을 시작하면 잔액에서 견적 금액을 따로 떼어 둡니다. 이것을 예약(hold)이라고 합니다. 이 금액은 그 영상에 들 수 있는 최대 금액이기도 합니다.
  • 영상이 성공하면 만들어진 만큼 청구됩니다. 예약 금액을 넘는 일은 없고, 남은 금액은 잔액으로 돌아갑니다.
  • 실패하거나 만료된 작업은 보통 예약 금액이 전액 해제됩니다. 다만 모델 페이지에 명시된 일부 콘텐츠 거부는 접수 시 견적 금액으로 과금됩니다. 최종 청구액은 settled와 cost로 확인하세요.
  • 새 계정에는 무료 제공량이 없으므로 먼저 잔액이 있어야 합니다. 과금을 보세요.

작동 방식

내 이미지 ──업로드──▶ spicy:// 주소(1일 동안 사용 가능)
                          │
내 문장 + 설정 ───────────┴──▶ 견적(무료) ──▶ 작업 시작(금액 예약)
                                                  │
                         queued ──▶ running ──▶ succeeded / failed / expired
                                                  │
                                        다운로드 링크(약 20분) ──▶ 내 파일

작업(task)은 생성 한 건을 말합니다. SpicyAPI가 백그라운드에서 처리하므로, 작업을 시작하는 것과 결과를 받는 것은 서로 별개의 동작입니다. 모든 작업에는 job_으로 시작하는 ID가 붙습니다. 이 ID로 작업을 다시 찾으니 꼭 적어 두세요. 이 페이지에 나오는 다른 용어는 용어집에서 설명합니다.

시작하기 전에

계정, 잔액, API 키 준비하기

먼저 계정 설정을 따라 하세요. 끝나면 다음이 갖춰져 있어야 합니다.

  • 잔액이 충전된 SpicyAPI 계정
  • sk-spicy-로 시작하는 API 키
  • SPICY_API_KEY라는 환경 변수에 넣어 둔 그 키. 환경 변수는 터미널이 자신이 실행하는 프로그램에 넘겨주는, 이름이 붙은 값입니다. 덕분에 키를 명령이나 코드에 직접 적을 필요가 없습니다.

지금 쓰고 있는 터미널 창에 키가 설정돼 있는지, 키 전체를 화면에 띄우지 않고 확인하세요.

echo "${SPICY_API_KEY:0:9}"

이렇게 보여야 합니다: sk-spicy-. 아무것도 나오지 않거나 오류가 나오면 이 창에는 키가 설정되지 않은 것입니다. 계정 설정으로 돌아가세요.

작업 폴더에 이미지 넣기

이 튜토리얼용 폴더를 만들고, 그 폴더에서 터미널을 여세요. 이 페이지의 모든 명령은 이 폴더에서 실행하며, 명령이 만드는 파일도 모두 이 폴더에 생깁니다.

mkdir -p ~/spicy-video
cd ~/spicy-video

이미지를 이 폴더에 복사하고 이름을 start-frame.jpg로 바꾸세요. PNG 파일이라면 start-frame.png로 하고, 이 페이지에 start-frame.jpg라고 적힌 곳마다 그 이름을 쓰면 됩니다.

좋은 시작 이미지의 조건은 다음과 같습니다.

  • 형식과 크기: JPEG, PNG, WebP, GIF이며 최대 10 MiB(약 10메가바이트)입니다. 모델에 따라 더 엄격한 자체 제한이 있을 수 있으며, 1단계에서 확인할 수 있습니다.
  • 파일이 실제로 그 형식이어야 합니다. SpicyAPI는 파일 이름만이 아니라 파일 내용을 검사합니다. 휴대폰 사진은 HEIC인 경우가 많은데, 이름만 .jpg로 바꿔서는 변환되지 않습니다. 먼저 사진을 열어 JPEG로 내보내거나 저장하세요.
  • 모양: 이미지가 영상의 첫 프레임이 됩니다. 가로 영상에는 가로로 긴 이미지를, 세로 영상에는 세로로 긴 이미지를 쓰세요. aspect_ratio 설정을 제공하는 모델도 있습니다.
  • 권리: 사용할 권리가 있는 이미지를 쓰세요.

고른 도구 준비하기

CLI는 터미널에서 실행하는 spicyapi라는 프로그램입니다. 한 번만 설치하면 됩니다(Node.js를 포함한 전체 설치 방법은 CLI: 시작하기 전에에 있습니다).

npm install -g @spicyapi/cli
spicyapi --version

설치가 EACCES로 실패하면 설치는 건너뛰고, 이 페이지에서 spicyapi라고 입력하는 곳마다 npx @spicyapi/cli를 입력하세요.

그다음 키가 작동하는지, 잔액이 있는지 확인하세요.

spicyapi balance

이렇게 보여야 합니다: 미국 달러로 표시된 available, held, total. available이 0보다 커야 합니다.

일곱 단계

MODEL_ID_FROM_CATALOG를 실제 모델 ID로 바꾸세요

MODEL_ID_FROM_CATALOG는 모델이 아니라 자리표시자입니다. 1단계에서 실시간 카탈로그(spicyapi models list, SDK의 listModels(), 또는 GET /api/v1/models)를 보고 실제 모델 ID를 고릅니다. 이 페이지에 자리표시자가 보이는 곳마다 그 ID를 붙여 넣으세요. 자리표시자를 그대로 보내면 "not found"(찾을 수 없음) 오류만 돌아옵니다.

Windows를 쓰나요? CLI나 SDK 탭을 고르세요

HTTP 탭은 bash용으로 작성했습니다. Windows PowerShell은 따옴표, 줄 바꿈(\), $(...)를 다르게 처리하므로 그 명령들은 적힌 그대로는 실행되지 않습니다. Windows에서는 CLI나 SDK 탭을 쓰거나, WSL(Linux용 Windows 하위 시스템, Windows Subsystem for Linux) 안에서 HTTP 명령을 실행하세요.

1. 모델 고르고 설정 읽기

할 일: 내 계정으로 쓸 수 있는 이미지→영상 모델을 나열하고, 하나를 고른 뒤, 그 모델이 받는 설정을 읽습니다.

모델을 나열합니다.

spicyapi models list --modality video --task image-to-video --json

이렇게 보여야 합니다: JSON 목록입니다. 아래는 줄인 것이며, 금액은 …로 표시했습니다.

{
  "total": 1,
  "items": [
    {
      "model": "MODEL_ID_FROM_CATALOG",
      "displayName": "Example video model",
      "modality": "video",
      "tasks": ["image-to-video"],
      "enabled": true,
      "available": true,
      "quantityField": "duration_seconds",
      "maxOutputDurationSeconds": 10,
      "taskTimeoutSeconds": 1800,
      "pricing": [
        { "variant": "720p", "unit": "per_second", "price": "…", "currency": "USD" },
        { "variant": "1080p", "unit": "per_second", "price": "…", "currency": "USD" }
      ]
    }
  ]
}

enabled와 available이 모두 true인 모델을 고르고, 그 model 값을 복사하세요. 그다음 설정을 읽습니다.

spicyapi models get MODEL_ID_FROM_CATALOG --json

응답에는 같은 필드에 더해 inputSchema(설정)와 examples(서버가 이미 검사한 입력값)가 들어 있습니다.

목록에서 확인할 것:

필드알려 주는 것
model이후 모든 단계에서 쓸 모델 ID
enabled, available둘 다 true인 모델만 쓰세요
pricing가격 단계마다 항목이 하나씩 있습니다. variant(그 가격이 적용되는 설정, 흔히 해상도), unit(영상은 보통 per_second), 미국 달러로 적힌 price입니다. 할인이 적용되면 regularPrice와 offerLabel이 함께 나옵니다
quantityField몇 단위만큼 과금할지 정하는 설정으로, 보통 duration_seconds입니다. 비어 있으면 영상 하나가 1단위입니다
maxOutputDurationSeconds모델이 허용하는 가장 긴 영상 길이
taskTimeoutSeconds생성이 expired로 멈추기 전까지 실행될 수 있는 시간(이렇게 멈추면 과금되지 않습니다)

설정 읽는 법. inputSchema는 JSON Schema로 작성된 모델의 설정 목록입니다.

  • required에는 반드시 보내야 하는 설정이 나열됩니다. 이런 종류의 모델에서는 image_url이 언제나 들어 있고, 대부분은 prompt도 필수입니다.
  • properties에는 모델이 받는 모든 설정이 나열됩니다. 설정마다 type과 쉬운 영어로 쓴 description이 있고, 흔히 enum(허용되는 값의 전부), minimum과 maximum, default(설정을 생략했을 때 쓰이는 값)도 있습니다.
  • 설정마다 들어 있는 x-ui는 화면 표시용 힌트입니다. x-ui.affects_price: true는 그 설정을 바꾸면 가격이 바뀐다는 뜻입니다.
  • 일부 모델은 "A를 보내면 B도 보내야 한다" 같은 조건을 최상위에 추가합니다. 읽는 법은 Spicy Schema 사양에서 설명합니다.
  • examples에는 서버가 이미 검사한 완전한 입력값이 들어 있어, 안전하게 시작할 수 있는 출발점이 됩니다.

가장 자주 만나는 설정. 이름은 모든 모델에서 같지만, 모델마다 그중 일부만 받으며 허용되는 값도 모델마다 다릅니다.

설정하는 일가격이 바뀌나요?
image_url첫 프레임으로 쓰이는 시작 이미지. 2단계에서 받은 spicy:// 주소나 공개 https:// 링크를 넣습니다아니요
prompt일어날 일: 움직임, 카메라, 분위기. 이미지에 이미 보이는 것을 되풀이하기보다 움직임을 묘사하세요보통 아니요
duration_seconds영상 길이(초). 허용되는 값은 enum에 있거나 minimum과 maximum 사이입니다. 일부 모델은 설정의 description에서 설명하는 특수한 값도 받습니다대부분의 모델에서 예. 영상은 보통 초 단위로 과금되므로 길수록 비쌉니다
resolution720p나 1080p 같은 출력 크기대개 예. 해상도가 높을수록 따로 더 높은 가격이 매겨지는 경우가 많습니다
aspect_ratio16:9, 9:16, 1:1 같은 영상 비율. 이미지 비율을 따라가는 adaptive를 제공하는 모델도 있습니다x-ui.affects_price를 확인하세요
generate_audio이미지에 어울리는 사운드트랙도 함께 생성일부 모델에서
last_image_url마지막 프레임용 이미지. 첫 프레임과 마지막 프레임을 보세요견적으로 확인하세요
negative_prompt영상에서 피해야 할 것보통 아니요
seed실행할 때마다 결과를 비교하기 쉽게 해 주는 숫자. 똑같은 영상이 나온다고 보장하지는 않습니다아니요

이 모델이 나열한 설정만 보내세요

모델마다 설정 목록이 따로 있습니다. 그 모델의 properties에 없는 설정, 철자가 틀린 이름, enum에 없는 값이 하나라도 있으면 요청 전체가 400으로 거부됩니다. 과금되지는 않지만, 다른 모델의 입력값을 확인하지 않고 복사하지는 마세요.

방금 일어난 일: 내 계정의 실시간 카탈로그를 내 가격까지 포함해 읽었습니다. 과금된 것은 없습니다. 카탈로그 조회도 계정의 요청 한도에 포함되므로, 영상을 만들 때마다 반복할 필요는 없습니다. 모델을 바꾸거나 400을 받았을 때 다시 하세요.

2. 이미지 업로드하기

할 일: start-frame.jpg를 업로드하고, 돌려받은 spicy:// 주소를 복사합니다. 업로드는 무료입니다.

spicyapi files upload start-frame.jpg

이렇게 보여야 합니다:

fileId: fil_01k3m8x9q2z4v7n5p6r8s0t1w3
status: ready
bytes: 402118
contentType: image/jpeg
sha256: a91f4c2e5b7d16809e3f2a4c8d0b61e7c4a890e5d2f71b3c609ae8427d15f0c6
uri: spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3
expiresAt: 2026-09-18T09:12:11Z

출력된 uri 값을 그대로 복사하세요.

방금 일어난 일: 이미지가 내 계정 전용으로 비공개 저장되고, 검사를 거쳐(실제 파일 형식이 지정한 형식과 일치해야 합니다) spicy:// 주소를 받았습니다. 이 주소는 웹 링크가 아닙니다. 내 계정만, 그것도 작업의 입력 안에서만 쓸 수 있습니다. 쓸 수 있는 기간은 1일이며(expiresAt 참고), 그 뒤에는 이미지를 다시 업로드하세요.

이미지가 이미 온라인에 있나요?

이미지가 로그인 없이 열리는 공개 https:// 주소에 이미 올라가 있다면, 이 단계를 건너뛰고 그 주소를 image_url에 넣어도 됩니다. 영상이 생성되는 동안 그 주소에 계속 접속할 수 있어야 합니다.

업로드가 실패하면:

보이는 메시지뜻할 일
Unsupported file type, 또는 CLI나 SDK가 파일 형식을 알 수 없다고 할 때파일이 JPEG, PNG, WebP, GIF가 아닙니다이미지를 변환하거나, 올바른 확장자로 이름을 붙이세요
File exceeds the 10 MB limit이미지가 10 MiB보다 큽니다더 작은 버전으로 내보내세요
The uploaded file does not match the upload ticket파일 내용이 이름이나 선언한 형식과 다릅니다. 예를 들어 HEIC 사진의 이름만 .jpg로 바꾼 경우입니다진짜 JPEG나 PNG로 내보내서 다시 업로드하세요
The upload ticket has expired티켓을 받은 뒤 확정하기까지 약 20분 넘게 지났습니다업로드를 처음부터 다시 하세요

3. 영상 묘사하고 가격 확인하기

할 일: 설정을 input.json이라는 파일에 적고, 견적을 요청합니다.

input.json 작성하기. 모든 이미지→영상 모델이 받는 두 가지 설정부터 시작하세요. prompt에는 내 문장을 넣고, image_url 값은 2단계에서 복사한 uri로 바꾸세요.

input.json
{
  "prompt": "The camera slowly pushes in while rain runs down the window and neon light flickers",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"
}

생략한 설정에는 모델의 default가 쓰입니다. 직접 정하고 싶다면 내 모델의 properties에 있는 설정만, 허용되는 값으로 추가하세요. 예를 들어 모델이 duration_seconds와 resolution을 나열하고 아래 값을 허용한다면 다음과 같이 씁니다.

{
  "prompt": "The camera slowly pushes in while rain runs down the window and neon light flickers",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "duration_seconds": 5,
  "resolution": "720p"
}

작업 폴더에 파일을 저장하세요.

줄 안에 내 문장과 uri를 넣은 다음, 모든 줄을 한꺼번에 붙여 넣으세요.

cat > input.json <<'EOF'
{
  "prompt": "The camera slowly pushes in while rain runs down the window and neon light flickers",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"
}
EOF

따옴표는 둥근 따옴표가 아니라 곧은 따옴표(")를 쓰고, 마지막 설정 뒤에는 쉼표를 붙이지 마세요.

견적 받기:

spicyapi tasks quote --model MODEL_ID_FROM_CATALOG --input-file input.json

이렇게 보여야 합니다(금액은 …로 표시):

quoteId: eyJ2IjoxLCJtIjoi…
model: MODEL_ID_FROM_CATALOG
estimatedCost: …
maxCharge: …
currency: USD
quantity: 5
unit: per_second
expiresAt: 2026-09-17T08:05:00Z

방금 일어난 일: SpicyAPI가 입력값을 모델의 설정과 대조해 검사하고, 바로 이 요청의 가격을 계산했습니다. 아무것도 시작되지 않았고, 아무것도 과금되지 않았습니다. estimatedCost는 지금 시작하면 예약될 금액이고, maxCharge는 청구될 수 있는 최대 금액입니다. quantity와 unit은 무엇에 대해 돈을 내는지, 예를 들어 5초라는 것을 보여 줍니다.

견적은 5분 동안, 그리고 바로 이 입력값에 대해서만 유효합니다. 길이나 해상도를 바꿔 다시 견적을 받으면 가격을 비교할 수 있습니다. 견적은 작업을 시작할 때와 같은 검사를 거치므로, 문제가 있다면 여기서 무료로 드러납니다. 400은 입력값이 모델의 설정과 맞지 않는다는 뜻이고(1단계를 참고해 input.json을 고치세요), 40201은 잔액이 모자란다는 뜻입니다. 나머지 코드는 7단계에 정리해 두었습니다.

내 이미지 없이 먼저 시험해 보고 싶나요?

1단계에서 본 모델의 examples는 서버가 이미 검사한 완전한 입력값입니다. 그중 하나를 그대로 input.json에 넣고 견적을 받은 뒤 생성해 보면, 내 이미지를 쓰기 전에 전체 흐름이 작동하는 것을 확인할 수 있습니다.

4. 생성 시작하기

이 단계는 비용이 듭니다

생성을 시작하면 견적 금액이 잔액에서 예약됩니다. SpicyAPI가 한 번 접수한 작업은 취소할 수 없습니다. 끝까지 실행되고, 성공하면 과금됩니다. 실패하거나 만료된 작업은 보통 예약 금액이 전액 해제됩니다. 다만 모델 페이지에 명시된 일부 콘텐츠 거부는 접수 시 견적 금액으로 과금됩니다. 최종 청구액은 settled와 cost로 확인하세요.

멱등 키를 쉬운 말로 풀면. 멱등 키는 주문 번호처럼 영상 하나에 붙이는 라벨입니다. 연결이 끊겨 영상이 시작됐는지 확실하지 않다면, 같은 요청을 같은 라벨로 다시 보내세요. SpicyAPI는 두 번째 영상을 시작해 과금하는 대신, 이미 시작한 작업을 돌려줍니다. 라벨은 같은 API 키로 24시간 동안 유효합니다. 다른 영상에는 새 라벨을 쓰세요. 같은 라벨을 다른 입력값과 함께 보내면 409로 거부됩니다. 자세한 내용은 멱등성에 있습니다.

할 일:

spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json

CLI가 견적을 다시 받아 가격을 보여 주고, 내 답을 기다립니다.

Estimated charge: USD …; maximum charge: USD …. Quote expires: 2026-09-17T08:05:00Z.
Idempotency-Key: 4f6755a5-0d72-4420-9f6b-9faf0e2b0241
Create a billable task with model MODEL_ID_FROM_CATALOG? … Continue? [y/N]

y를 입력하고 Enter 키를 누르세요. 그 밖의 답은 모두 취소로 처리되며, 아무것도 과금되지 않습니다. 답하기 전에 Idempotency-Key 값을 어딘가에 복사해 두세요. CLI는 실행할 때마다 새 라벨을 만들기 때문에, 연결이 끊기면 바로 이 라벨이 필요합니다.

이렇게 보여야 합니다:

idempotencyKey: 4f6755a5-0d72-4420-9f6b-9faf0e2b0241
taskId: job_01k3m8x9q2z4v7n5p6r8s0t1w3
state: queued
estimatedCost: …
deadlineAt: 2026-09-17T08:35:00Z

taskId를 복사하세요.

방금 일어난 일: SpicyAPI가 생성을 접수했습니다. 이제 이것은 작업이며, 잔액에서 estimatedCost만큼이 예약됐습니다. 이 금액이 이 영상에 들 수 있는 최대 금액이기도 합니다. state: queued는 차례를 기다리고 있다는 뜻입니다. deadlineAt은 작업이 끝날 수 있는 가장 늦은 시각이며, 그때까지 끝나지 않으면 expired로 끝나고 아무것도 과금되지 않습니다. deadlineAt은 파일이 만료되는 시각이 아닙니다.

견적을 함께 넘긴다는 것은 "내가 본 가격일 때만 접수해 달라"는 뜻입니다. 그사이 가격이나 입력값이 바뀌었다면, 다른 금액을 예약하는 대신 요청을 40901로 거부합니다. CLI는 이 일을 알아서 해 줍니다.

연결이 끊겨 작업 ID를 보지 못했다면 새 라벨로 그냥 다시 시작하지 마세요. 그러면 두 번째 영상이 만들어지고 그 비용까지 청구됩니다. 같은 라벨로 요청을 반복하세요.

  • CLI: spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json --idempotency-key <the value you copied>(<the value you copied> 자리에는 복사해 둔 Idempotency-Key 값을 넣습니다). 기다리기가 중단된 작업 다시 이어 가기를 보세요.
  • SDK: node generate.mjs --yes를 다시 실행하세요. idempotency-key.txt를 그대로 다시 씁니다.
  • HTTP: "영상 시작하기" 블록을 다시 실행하세요. idempotency-key.txt를 그대로 다시 씁니다.

4단계가 거부됐다면 아무것도 만들어지지 않았고, 과금되지도 않았습니다. 이유와 해결 방법은 7단계에 있습니다.

5. 영상 기다리기

할 일: 작업이 끝날 때까지 상태를 확인합니다. 영상은 보통 몇 분 걸립니다.

spicyapi tasks wait job_01k3m8x9q2z4v7n5p6r8s0t1w3 --wait-timeout-ms 1800000 --json

작업 ID는 내 것으로 바꾸세요. --wait-timeout-ms 1800000을 붙이면 기본값인 10분 대신 최대 30분까지 기다립니다.

끝나면 이렇게 보여야 합니다(줄인 것):

{
  "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "model": "MODEL_ID_FROM_CATALOG",
  "state": "succeeded",
  "output": {
    "assets": [
      {
        "key": "tasks/2026/09/17/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4",
        "url": "https://…",
        "expiresAt": "2026-09-17T08:40:00Z",
        "mime": "video/mp4",
        "durationSeconds": 5,
        "width": 1280,
        "height": 720,
        "bytes": 4839211
      }
    ]
  },
  "cost": "…",
  "settled": true
}

다음번에는 tasks create에 --wait를 붙여 4단계와 5단계를 한 번에 할 수 있습니다.

방금 일어난 일: 도구가 몇 초마다 SpicyAPI에 작업 상태를 물었습니다. 상태는 queued(대기 중), running(생성 중)을 거쳐 최종 상태 하나로 끝납니다. succeeded, failed, expired 중 하나입니다. 성공한 뒤에는 파일이 SpicyAPI 자체 저장소로 복사되는데, 몇 초가 더 걸립니다. 그동안 결과에는 pending: true가 표시됩니다. settled가 true가 되면 cost가 최종 금액입니다.

  • 터미널을 닫거나 Ctrl + C를 눌러도 작업은 취소되지 않습니다. 기다리기만 멈춥니다. 작업 ID를 보관해 두었다가 나중에 이 단계를 다시 실행하세요.
  • 몇 초에 한 번보다 자주 확인하지 마세요. 작업 조회는 새 작업 제출과 독립된 계정 읽기 허용량을 사용합니다. 호출 제한을 참고하세요.
  • 앱이나 서버라면 계속 물어보는 대신, 작업이 끝났을 때 SpicyAPI가 알려 주게 하세요. 기다리지 말고 알림 받기를 보세요.

6. 영상 내려받아 보관하기

할 일: 새 다운로드 링크를 받아 파일을 내 컴퓨터에 저장합니다.

새 링크를 받습니다.

spicyapi files download-url job_01k3m8x9q2z4v7n5p6r8s0t1w3
key: tasks/2026/09/17/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4
url: https://…
expiresAt: 2026-09-17T08:52:00Z

url을 브라우저에 붙여 넣어 내려받거나, 터미널에서 저장하세요. 링크에 & 문자가 들어 있으므로 따옴표는 그대로 두세요.

curl -L -o my-video.mp4 "PASTE_THE_URL_HERE"

Windows PowerShell에서는 curl 대신 curl.exe를 입력하세요. 작업이 파일을 여러 개 만들었다면 spicyapi tasks get <task-id> --json으로 목록을 보고, --key로 그중 하나를 고르세요.

방금 일어난 일: 모든 결과에는 직접 다운로드 링크가 딸려 옵니다. 링크는 약 20분 동안 유효하고 API 키가 필요 없습니다. 링크에 키를 절대 붙이지 마세요. 링크가 만료되면 작업을 다시 조회하거나 files download-url을 써서 새 링크를 받으세요.

내 사본을 따로 보관하세요

SpicyAPI는 생성된 파일을 최대 약 14일 동안 보관하며(계정의 보관 기간 설정이 더 짧으면 그보다 짧게), 그 뒤에는 영구히 삭제합니다. 업로드한 이미지는 1일 동안 쓸 수 있고, 프롬프트 텍스트는 기본적으로 30일 뒤에 지워집니다. 작업 기록과 비용 기록은 남습니다. 끝난 작업의 파일과 프롬프트를 더 일찍 지우려면 spicyapi tasks purge, purgeTask(), POST /api/v1/jobs/purge 중 하나를 쓰세요. 내용만 지울 뿐 환불은 아닙니다. 데이터 보관과 파기를 보세요.

7. 문제가 생겼을 때

문제는 두 종류가 있고, 대처 방법이 서로 다릅니다.

요청이 거부되는 경우. 명령이나 호출이 곧바로 오류를 받습니다. 아무것도 만들어지지 않았고, 아무것도 과금되지 않았습니다. 메시지가 이유를 알려 주며, 오류에는 code와 함께 지원팀에 문의할 때 알려 줄 요청 ID(req_…)가 들어 있습니다.

코드뜻할 일
400, 또는 400으로 시작하는 더 구체적인 코드입력값이 모델의 설정과 맞지 않습니다. 필수 설정이 빠졌거나, 모르는 설정이나 철자가 틀린 설정이 있거나, 허용되지 않는 값이거나, 만료됐거나 다른 계정의 spicy:// 주소이거나, 모델이 지금 처리할 수 없는 설정 조합이거나, 콜백 주소가 잘못된 경우입니다input.json을 1단계의 설정과 비교해 고치세요. 주소가 만료됐다면 이미지를 다시 업로드하세요
401API 키가 없거나, 잘못 입력됐거나, 폐기됐습니다시작하기 전에에서 한 것처럼 SPICY_API_KEY를 확인하세요
40201잔액이 예약할 금액에 못 미칩니다콘솔의 결제에서 충전하세요
40202키에 걸린 지출 한도(일, 월, 누적)에 도달했습니다API 키 페이지에서 한도를 올리거나, 한도가 초기화될 때까지 기다리세요
403, 40301이 키로는 이 모델을 쓸 수 없거나, 허용되지 않은 곳에서 요청이 왔습니다API 키 페이지에서 키의 허용 모델과 IP 허용 목록을 확인하세요
404내 계정에 그 ID의 모델이 없거나(또는 자리표시자를 그대로 보냈거나), 이 키로 만든 그 ID의 작업이 없습니다정확한 ID를 다시 복사하세요. 작업을 만든 키와 같은 키를 쓰세요
409이 멱등 키가 이미 다른 요청에 쓰였습니다새 영상에는 새 라벨을 쓰세요
40901견적이 만료됐거나(5분) 가격이 바뀌었습니다견적을 다시 받은 뒤 다시 시작하세요
429짧은 시간에 요청이 너무 많았습니다오류가 알려 주는 초만큼 기다린 뒤, 더 천천히 이어 가세요
50301모델이 지금은 새 작업을 받을 수 없습니다나중에 다시 시도하거나 다른 모델을 고르세요

작업이 실패하는 경우. 작업은 접수됐지만 succeeded가 아니라 failed나 expired로 끝납니다. 작업에는 이유를 알려 주는 errorCode와, 더 자세한 설명이 문장으로 담긴 errorMessage가 표시됩니다. 실패하거나 만료된 작업은 보통 예약 금액이 전액 해제됩니다. 다만 모델 페이지에 명시된 일부 콘텐츠 거부는 접수 시 견적 금액으로 과금됩니다. 최종 청구액은 settled와 cost로 확인하세요.

다음과 같이 확인하세요.

spicyapi tasks get job_01k3m8x9q2z4v7n5p6r8s0t1w3

state, errorCode, errorMessage를 보세요.

그다음 메시지 문구가 아니라 errorCode를 보고 무엇을 할지 정하세요.

errorCode뜻할 일
rate_limited, upstream_unavailable, upstream_failed생성 쪽이 붐볐거나 일시적으로 쓸 수 없었습니다잠시 뒤 다시 실행하세요
timeout(또는 상태가 expired)영상이 제시간에 완성되지 않았습니다한 번 더 시도하세요. 또 그렇다면 길이를 줄이거나 해상도를 낮춰 새 작업을 시작하세요
generation_failed생성은 실행됐지만 아무것도 만들어지지 않았습니다같은 입력값은 보통 같은 식으로 실패합니다. 프롬프트나 이미지를 바꿔 새 작업을 시작하세요
invalid_asset이미지를 쓸 수 없었습니다. 예를 들어 업로드가 만료됐거나 파일을 읽을 수 없었던 경우입니다이미지를 다시 업로드하고, 새 주소로 새 작업을 시작하세요
invalid_request, unsupported_combination설정이 받아들여지지 않았습니다설정을 바꿔 새 작업을 시작하세요
content_rejected선택한 모델이 자체 정책에 따라 이 요청을 거절했습니다프롬프트나 이미지를 바꾸거나, 다른 모델을 고르세요

그 밖의 값은 upstream_failed와 똑같이 다루세요. 전체 목록은 오류에 있습니다.

실패한 작업 다시 실행하기. 다시 시도하면 같은 모델과 입력값으로 새 작업이 만들어지며, 모델의 현재 가격이 적용됩니다. 4단계와 마찬가지로 비용이 들고, 원래 입력값을 그대로 씁니다. 원래 입력값이 이미 만료된 업로드를 쓰고 있었다면, 다시 시도하지 말고 이미지를 다시 업로드해 새 작업을 시작하세요.

spicyapi tasks retry job_01k3m8x9q2z4v7n5p6r8s0t1w3 --wait --wait-timeout-ms 1800000

확인을 요청하지만, tasks create와 달리 가격을 먼저 보여 주지는 않습니다. 가격을 보려면 3단계의 tasks quote 명령을 실행하세요.

다시 시도할 수 있는 것은 failed와 expired 작업뿐입니다. 성공한 영상을 다른 버전으로 만들고 싶다면 새 라벨로 3단계부터 다시 하세요. 한 번 접수된 작업은 취소할 방법이 없습니다. 자세한 내용은 작업 확정과 재시도에 있습니다.

대신 AI 어시스턴트로 진행하기

Claude Code, Cursor, Codex처럼 MCP를 지원하는 AI 어시스턴트를 쓴다면, SpicyAPI MCP 서버를 통해 어시스턴트가 일곱 단계를 모두 대신 진행해 줍니다. MCP 서버: 클라이언트 설정하기를 따라 한 번만 설정해 두고, 평소 쓰는 말로 요청하세요. 예를 들면 다음과 같습니다.

/Users/me/spicy-video/start-frame.jpg에 있는 이미지를 SpicyAPI에 업로드해 주세요. 내 키로 쓸 수 있는 이미지→영상 모델을 찾아서, 가장 저렴한 두 모델로 5초짜리 클립 견적을 받아 주세요. 제가 확인하면 더 저렴한 쪽으로 영상을 생성하고, 끝날 때까지 기다렸다가 다운로드 링크를 알려 주세요.

Windows에서는 경로를 C:\Users\me\spicy-video\start-frame.jpg처럼 적으세요.

진행 과정은 다음과 같습니다.

  1. spicyapi_upload_file이 이미지를 업로드하고 spicy:// 주소를 받습니다. 무료이지만 파일을 실제로 전송하므로, 어떤 파일인지 정확히 지정하세요. 기본적으로는 홈 폴더 안의 파일만 읽을 수 있습니다. 로컬 파일을 보세요.
  2. spicyapi_models_list와 spicyapi_model_get이 모델과 그 설정을 찾고, spicyapi_task_quote가 선택지별 가격을 확인합니다. 모두 무료입니다.
  3. spicyapi_task_create는 실행을 멈추고 나에게 확인을 요청합니다. 모델, 예상 청구 금액과 최대 청구 금액, 견적이 만료되는 시각을 보여 줍니다. 내가 확인하기 전에는 아무것도 과금되지 않으며, 어시스턴트가 대신 확인할 수는 없습니다.
  4. spicyapi_task_wait는 한 번에 최대 5분까지 기다리므로, 영상이 오래 걸리면 어시스턴트가 여러 번 기다릴 수 있습니다. 끝나면 약 20분 동안 유효한 다운로드 링크를 건네줍니다.

더 많은 예시와 모든 도구는 MCP 서버에 있습니다.

더 나아가기

첫 프레임과 마지막 프레임

일부 이미지→영상 모델은 last_image_url도 받습니다. 영상이 끝나는 장면으로 쓸 두 번째 이미지입니다. 1단계에서 본 properties에 last_image_url이 있는지 찾아보면 내 모델이 지원하는지 알 수 있습니다. 없다면 그 모델은 지원하지 않으며, 보내면 400으로 거부됩니다.

2단계처럼 이미지 두 장을 모두 업로드한 뒤, 두 주소를 input.json에 넣으세요.

{
  "prompt": "The flower slowly opens as morning light spreads across the table",
  "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "last_image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w4"
}

그 모델이 마지막 이미지를 어떻게 쓰는지는 설정의 description에 설명돼 있습니다. 두 번째 이미지 때문에 가격이 달라지는지 보려면, 시작하기 전에 견적을 다시 받으세요.

영상 여러 개 만들기

  • 업로드를 재사용하세요. spicy:// 주소 하나는 expiresAt까지 여러 작업에 쓸 수 있습니다. 단, 계정의 업로드 보관 설정이 작업이 끝나는 즉시 업로드를 지우도록 되어 있다면 그렇지 않습니다.
  • 영상 하나에 라벨 하나. campaign-clip-1, campaign-clip-2처럼 영상마다 멱등 키를 따로 붙이세요. 그러면 스크립트를 다시 실행해도 이미 시작한 영상을 돌려받을 뿐, 두 번 돈을 내지 않습니다.
  • 한꺼번에 모두 시작하지 마세요. 실행 중인 작업마다 금액이 예약되고, 지출 한도를 넘는 작업은 40202로 거부되며, 상태를 확인할 때마다 요청 한도에 포함됩니다. 한 번에 두 개씩으로 시작하세요.

바로 쓸 수 있는 스크립트는 동시 실행 수를 제한해 일괄 처리하기(SDK)와 스크립트에서 CLI 실행하기에 있습니다.

기다리지 말고 알림 받기

웹사이트나 백그라운드 서비스에서 "다 됐나요?"라고 묻기 위해서만 프로그램을 계속 돌려 두는 것은 낭비입니다. 그 대신 작업에 콜백 주소를 알려 주세요. 콜백 주소는 내 서버에 있는 공개 웹 주소로, 작업이 끝나면 SpicyAPI가 5단계에서 보는 것과 같은 작업 정보를 담아 한 번 호출합니다.

필요한 것:

  • 인터넷에서 표준 포트의 https:// 주소로 접속할 수 있는 서버(localhost는 거부됩니다)
  • 콘솔에서 받는 웹훅 서명 키. 내 서버가 각 호출이 정말 SpicyAPI에서 왔는지 확인하는 데 씁니다
  • 서명을 확인하고, 빠르게 응답하고, 같은 알림이 두 번 와도 문제없이 처리하는 코드

형식, 서명, 재전송 일정은 웹훅에서 설명하며, SDK 문서에 최소한의 수신기가 있습니다. 대비책도 마련해 두세요. deadlineAt이 한참 지났는데도 알림이 오지 않은 작업은 가끔 직접 확인하세요.

견적을 받을 때와 작업을 시작할 때 콜백 주소를 추가하세요.

spicyapi tasks create --model MODEL_ID_FROM_CATALOG --input-file input.json --callback-url https://your-app.example.com/hooks/spicy

CLI는 자체적으로 받는 견적에도 이 주소를 넣으므로, 가격 확인이 그대로 들어맞습니다.

다음 단계

이 페이지에서