# 영상 — /v1/videos

> 글(과 그림 한 장)로 짧은 영상을 만듭니다. 만들고, 끝났는지 보고, 받습니다.

> 원문: https://schoolorder.kr/docs/reference/videos

영상은 몇십 초에서 몇 분 걸려서 한 번의 호출로 기다리지 않아요. 만들기를 부르면 바로 작업 id 가 오고, 그 id 로 끝났는지 보다가, 끝나면 mp4 를 받으세요. OpenAI /v1/videos 모양 그대로라 공식 SDK 의 videos.create · retrieve · download_content 가 그대로 붙어요.

**만들기 → 끝났는지 보기 → 받기**

```bash
# 1) 만들기 — 몇 초 안에 id 가 와요
curl https://schoolorder.kr/v1/videos \
  -H "Authorization: Bearer $SCHOOLORDER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"grok-imagine-video","prompt":"칠판 앞에서 분필로 하트를 그리는 손, 따뜻한 햇살","seconds":"4","size":"1280x720"}'

# 2) 끝났는지 보기 — status 가 completed 가 될 때까지 5초마다
curl https://schoolorder.kr/v1/videos/video_… -H "Authorization: Bearer $SCHOOLORDER_API_KEY"

# 3) 받기 — 짧게 유효한 주소로 넘겨드려요(-L 로 따라가 주세요)
curl -L https://schoolorder.kr/v1/videos/video_…/content -H "Authorization: Bearer $SCHOOLORDER_API_KEY" -o clip.mp4
```

**공식 SDK (openai-python)**

```python
import os
from openai import OpenAI
client = OpenAI(base_url="https://schoolorder.kr/v1", api_key=os.environ["SCHOOLORDER_API_KEY"])
video = client.videos.create_and_poll(model="grok-imagine-video", prompt="종이배가 잔잔한 호수 위를 떠가는 모습", seconds="4")
if video.status == "completed":
    client.videos.download_content(video.id).write_to_file("clip.mp4")
```

## 요청 파라미터

**만들기 — POST /v1/videos (JSON 또는 multipart/form-data)**

| 파라미터 | 받는 값 | 저희가 하는 일 |
| --- | --- | --- |
| `model` (필수) | 영상 모델 id | 글·그림 모델을 넣으시면 400 으로 맞는 문을 알려드려요. |
| `prompt` (필수) | 문자열(32,000자까지) | 손대지 않고 벤더에 닿아요. 벤더 안전 기준에 걸리면 status 가 failed, error.code 가 moderation_blocked 로 와요. |
| `seconds` | "4" 같은 문자열 또는 1~15 정수 | 안 적으시면 4초예요. 벤더에 이 길이를 **그대로 적어** 보내서, 미리 잡는 금액과 실제로 떼는 금액이 같은 자로 재져요. |
| `size` | 1280x720 · 720x1280 · 720x720 · 854x480 · 480x854 · 480x480 · 1920x1080 · 1080x1920 · 1080x1080 | 해상도와 화면비로 풀어서 벤더에 넘겨요. 모델이 안 만드는 해상도면(예: grok-imagine-video 의 1080p) 400 이에요. |
| `resolution · aspect_ratio` | 480p · 720p · 1080p / 16:9 · 9:16 · 1:1 · 4:3 · 3:4 · 3:2 · 2:3 | size 대신 이 둘로 보내셔도 돼요. 둘 다 오면 size 가 이겨요. |
| `input_reference · image_url` | 그림 파일(multipart, 4MB) 또는 https·data URI | 그림 한 장에서 시작하는 영상이에요. 파일은 저희가 data URI 로 바꿔 벤더에 넘기고, 주소는 그대로 넘겨요 — 저희 서버가 그 주소를 열지 않아요. |
| `generate_audio` | true · false | 기본은 소리 있음이에요. 꺼도 값은 같아요(09-30 실측). |
| `Idempotency-Key (헤더)` | 문자열 | 같은 키로 다시 보내시면 새로 만들지 않고 처음 작업을 돌려드려요. 네트워크가 끊겨 다시 보낼 때 두 번 값이 나가지 않게 넣어 주세요. |

## 응답 · 상태

status 는 queued → in_progress → completed 또는 failed 넷 중 하나예요. 끝나면 usage 칸에 초 · 해상도 · 실제로 뗀 값(cost_usd)이 붙어요. 실패하면 error.code 로 이유를 말씀드려요 — moderation_blocked(안전 기준) · vendor_failed · timed_out · undelivered.

**끝난 작업 (줄임)**

```json
{
  "id": "video_0f8fad5b-d9cb-469f-a165-70867728950e",
  "object": "video",
  "model": "grok-imagine-video",
  "status": "completed",
  "progress": 100,
  "seconds": "4",
  "size": "1280x720",
  "created_at": 1790000000,
  "completed_at": 1790000031,
  "expires_at": 1790604831,
  "error": null,
  "usage": { "seconds": 4, "resolution": "720p", "cost_usd": 0.28 }
}
```

## 값은 어떻게 매겨지나요

만들기를 부르는 순간 「초 × 해상도의 초당 값」을 먼저 잡아두고, 끝나면 벤더가 실제로 매긴 값을 떼요. 저희가 재 보니 그 둘이 1원도 다르지 않았어요. 벤더가 만들지 못했거나 20분 안에 끝나지 않으면 떼지 않아요.

> **받은 영상은 7일 보관해요**
>
> 7일이 지나면 파일을 지워요 — expires_at 을 보시고 그 전에 받아 두세요. 지우고 싶으시면 DELETE /v1/videos/{id} 로 바로 지울 수 있어요(값은 돌아가지 않아요). 목록은 GET /v1/videos 예요.

## 이 문이 받는 모델

#### 영상 — `POST /v1/videos`

| model | 요금 |
| --- | --- |
| grok-imagine-video | 480p $0.05 / 초 · 720p $0.07 / 초 |
| grok-imagine-video-1.5 | 1080p $0.25 / 초 · 480p $0.08 / 초 · 720p $0.14 / 초 |

