> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apimart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Grok 공식 비디오 모델

> grok-imagine-video와 grok-imagine-video-1.5로 텍스트나 참조 이미지에서 비디오를 생성하고 Base 모델로 원본 비디오를 편집합니다.

<Info>
  이 페이지는 공식 모델 `grok-imagine-video`와 `grok-imagine-video-1.5`용입니다. 기존 `grok-imagine-1.5-video-ext`와 다른 모델이므로 이름과 매개변수를 섞지 마세요.
</Info>

<Warning>
  API Key를 브라우저, 공개 환경 변수, LocalStorage, URL 또는 프런트엔드 로그에 노출하지 마세요. 백엔드나 BFF에서 APIMart를 호출하세요.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.apimart.ai/v1/videos/generations \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'Idempotency-Key: 7d0141e4-a19a-4650-a717-dab777b3a330' \
    --data '{
      "model": "grok-imagine-video",
      "prompt": "A cinematic aerial shot of a coastal city at sunrise",
      "duration": 5,
      "resolution": "720p",
      "aspect_ratio": "16:9",
      "nsfw_check": true
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.apimart.ai/v1/videos/generations", {
    method: "POST",
    headers: {
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
      Accept: "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      model: "grok-imagine-video",
      prompt: "Improve motion consistency and apply cinematic color grading",
      video: { url: "https://cdn.example.com/source-video.mp4" },
    }),
  });

  console.log(response.status, await response.json());
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "code": 200,
    "data": [{
      "status": "submitted",
      "task_id": "task_01M09Y4Y101HTFFPV2QPW9DQ3W"
    }]
  }
  ```

  ```json 400 theme={null}
  {
    "error": {
      "message": "Invalid request parameters",
      "type": "invalid_request_error",
      "param": "resolution",
      "code": "invalid_request_error"
    }
  }
  ```
</ResponseExample>

## 연동 개요

모든 모드는 같은 비동기 엔드포인트를 사용합니다.

```http theme={null}
POST https://api.apimart.ai/v1/videos/generations
```

| 요청 필드                    | 모드           | 모델                    |
| ------------------------ | ------------ | --------------------- |
| `image_urls`와 `video` 없음 | 텍스트-투-비디오    | 두 모델                  |
| `image_urls`             | 참조 이미지-투-비디오 | 두 모델                  |
| `video`                  | 비디오 편집       | `grok-imagine-video`만 |

제출 후 `data[0].task_id`를 저장하고 다음을 폴링합니다.

```http theme={null}
GET https://api.apimart.ai/v1/tasks/{task_id}
```

<Warning>
  `X-APIMart-Response-Version`을 보내지 마세요. HTTP `202` 형식으로 전환되며 이 페이지는 이전 HTTP `200` 비동기 형식을 사용합니다.
</Warning>

## 모델 기능

| 기능                | `grok-imagine-video` | `grok-imagine-video-1.5` |
| ----------------- | :------------------: | :----------------------: |
| 텍스트-투-비디오         |           ✅          |             ✅            |
| 단일 또는 여러 참조 이미지   |           ✅          |             ✅            |
| 비디오 편집            |           ✅          |             ❌            |
| `480p`            |           ✅          |             ✅            |
| `720p`            |           ✅          |             ✅            |
| `1080p`           |           ❌          |             ✅            |
| 길이: 1\~15초, 기본 8초 |         1–15         |           1–15           |
| 프롬프트              |        1–8000        |          1–8000          |

```text theme={null}
duration     = 8
resolution   = 480p
aspect_ratio = auto
```

공개 계약에는 참조 이미지 수의 고정 상한이 없습니다. 유효한 URL의 비어 있지 않은 배열과 원래 순서를 유지하고 이미지 모델 제한을 재사용하지 마세요.

## 요청 헤더

<ParamField header="Authorization" type="string" required>
  `Bearer <APIMART_API_KEY>`
</ParamField>

<ParamField header="Content-Type" type="string" required>
  항상 `application/json`을 사용합니다.
</ParamField>

<ParamField header="Accept" type="string">
  `application/json`
</ParamField>

<ParamField header="Idempotency-Key" type="string">
  `Idempotency-Key`는 선택 사항이지만 유료 요청에는 강력히 권장합니다. 표시 가능한 ASCII 1\~191자를 지원하며 UUID를 권장합니다. 네트워크 재시도에는 원래 Key와 동일한 body를 사용하고 결과가 불확실할 때 Key를 바꾸지 마세요.

  새 논리 작업마다 새 Key를 사용합니다. 같은 작업 재시도는 원래 Key와 동일한 body를 재사용합니다.
</ParamField>

## 요청 매개변수

### 공통 필드

<ParamField body="model" type="string" required>
  공식 모델명. 비디오 편집은 Base만 지원

  * `grok-imagine-video`
  * `grok-imagine-video-1.5`
</ParamField>

<ParamField body="prompt" type="string" required>
  비어 있지 않은 지시문, 최대 8000 Unicode 문자

  `Array.from(prompt).length`
</ParamField>

<ParamField body="nsfw_check" type="boolean" default={false}>
  비디오 작업 제출 전에 콘텐츠 검토를 실행할지 지정합니다.

  * `true`: `omni-moderation-latest`로 프롬프트와 입력 이미지를 검토합니다
  * `false` 또는 생략: 검토 요청을 보내지 않아 검토 비용이나 지연이 추가되지 않습니다(기본값)
</ParamField>

### 생성 필드

<ParamField body="duration" type="integer" default={8}>
  생성 전용. 1\~15 정수, 기본 8
</ParamField>

<ParamField body="resolution" type="string" default="480p">
  Base: `480p/720p`, 1.5: `480p/720p/1080p`, 기본 `480p`

  * `grok-imagine-video`: `480p`, `720p`
  * `grok-imagine-video-1.5`: `480p`, `720p`, `1080p`
</ParamField>

<ParamField body="aspect_ratio" type="string" default="auto">
  생성 전용. `auto`, `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`

  * `auto`
  * `1:1`, `16:9`, `9:16`
  * `4:3`, `3:4`, `3:2`, `2:3`
</ParamField>

<ParamField body="image_urls" type="string[]">
  선택적 참조 이미지 배열. 각 항목은 공개 HTTPS URL. 비면 생략

  * 각 항목은 공개 HTTPS URL이어야 하며 상대 URL, Data URL, 원시 Base64는 지원하지 않습니다.
  * `image`, `images`, `input_reference` 같은 별칭 필드를 보내지 마세요.
  * 배열 순서는 유지됩니다. 중복 URL은 여러 입력 슬롯을 차지하며 중복 과금될 수 있습니다.
</ParamField>

### 비디오 편집 필드

<ParamField body="video" type="object">
  원본 비디오 `{url}`은 공개 HTTPS URL. Base만 지원

  <Expandable title="URL">
    <ParamField body="url" type="string" required>
      HTTPS
    </ParamField>
  </Expandable>
</ParamField>

비디오 편집에는 `model`, `prompt`, `video`가 필요하며 `nsfw_check`는 선택 사항입니다. `duration`, `resolution`, `aspect_ratio`, `image_urls`는 보내지 않으며 플랫폼이 원본 길이를 감지합니다.

## TypeScript 요청 타입

판별 유니온을 사용해 생성 전용 필드가 편집 요청에 들어가지 않게 합니다.

```ts theme={null}
type GrokVideoModel =
  | "grok-imagine-video"
  | "grok-imagine-video-1.5";

type GrokVideoResolution = "480p" | "720p" | "1080p";

type GrokVideoAspectRatio =
  | "auto"
  | "1:1"
  | "16:9"
  | "9:16"
  | "4:3"
  | "3:4"
  | "3:2"
  | "2:3";

interface GrokVideoGenerateRequest {
  model: GrokVideoModel;
  prompt: string;
  nsfw_check?: boolean;
  duration?: number;
  resolution?: GrokVideoResolution;
  aspect_ratio?: GrokVideoAspectRatio;
  image_urls?: string[];
}

interface GrokVideoEditRequest {
  model: "grok-imagine-video";
  prompt: string;
  nsfw_check?: boolean;
  video: { url: string };
}

type GrokVideoRequest =
  | GrokVideoGenerateRequest
  | GrokVideoEditRequest;
```

## 요청 예시

<Tabs>
  <Tab title="텍스트-투-비디오">
    ```json theme={null}
    {"model":"grok-imagine-video","prompt":"A cinematic aerial shot at sunrise","duration":5,"resolution":"720p","aspect_ratio":"16:9"}
    ```
  </Tab>

  <Tab title="1.5 · 1080p">
    ```json theme={null}
    {"model":"grok-imagine-video-1.5","prompt":"A smooth studio product commercial","duration":5,"resolution":"1080p","aspect_ratio":"16:9"}
    ```
  </Tab>

  <Tab title="단일 또는 여러 참조 이미지">
    ```json theme={null}
    {
      "model":"grok-imagine-video-1.5",
      "prompt":"Use the first image as subject and the second as style",
      "duration":5,
      "resolution":"720p",
      "aspect_ratio":"16:9",
      "image_urls":[
        "https://cdn.example.com/subject.jpg",
        "https://cdn.example.com/style.jpg"
      ]
    }
    ```
  </Tab>

  <Tab title="비디오 편집">
    ```json theme={null}
    {
      "model":"grok-imagine-video",
      "prompt":"Improve motion consistency and apply cinematic color grading",
      "video":{"url":"https://cdn.example.com/source.mp4"}
    }
    ```
  </Tab>
</Tabs>

## 비동기 작업

### 생성 성공

생성 성공 시 HTTP `200`을 반환합니다. `data[0].task_id`를 저장하세요. 제출은 완료를 의미하지 않습니다. 작업 ID는 제출을 뜻하며 완료를 뜻하지 않습니다.

```json theme={null}
{
  "code":200,
  "data":[{"status":"submitted","task_id":"task_01M09Y4Y101HTFFPV2QPW9DQ3W"}]
}
```

### 작업 조회

```http theme={null}
GET https://api.apimart.ai/v1/tasks/{task_id}
Authorization: Bearer <APIMART_API_KEY>
Accept: application/json
```

`GET /v1/tasks/{task_id}`를 3\~5초마다 조회합니다. 새로고침 후 저장된 ID로 재개합니다.

| `data.status` | 의미           | 동작              |
| ------------- | ------------ | --------------- |
| `pending`     | 대기 중         | 계속 조회           |
| `processing`  | 생성 중         | 진행률 표시          |
| `completed`   | 완료           | 결과 읽고 중지        |
| `failed`      | 실패 및 환불      | 오류 표시 후 중지      |
| `unknown`     | 일시적으로 알 수 없음 | 빈도를 낮추고 나중에 재시도 |

### 완료 응답

```json theme={null}
{
  "code":200,
  "data":{
    "id":"task_xxx",
    "status":"completed",
    "progress":100,
    "created":1787040038,
    "completed":1787040081,
    "actual_time":43,
    "estimated_time":100,
    "cost":0.072,
    "credits_cost":0.72,
    "result":{"videos":[{"url":["https://cdn.example.com/result.mp4"],"expires_at":1787126481}]}
  }
}
```

`result.videos[0].url`은 단일 문자열이 아니라 문자열 배열입니다. 각 값을 HTTPS URL로 검증하세요. 런타임 검증을 권장합니다.

```ts theme={null}
function extractVideoURLs(payload: unknown): string[] {
  const groups = (payload as any)?.data?.result?.videos;
  if (!Array.isArray(groups)) return [];

  return groups.flatMap((group: any) =>
    Array.isArray(group?.url)
      ? group.url.filter(
          (url: unknown): url is string =>
            typeof url === "string" && /^https:///i.test(url),
        )
      : [],
  );
}
```

만료는 `expires_at`을 사용합니다. 고정 시간을 넣지 말고 다운로드 또는 저장을 안내하세요.

### 실패 응답

```json theme={null}
{
  "code":200,
  "data":{
    "id":"task_xxx",
    "status":"failed",
    "progress":100,
    "cost":0,
    "credits_cost":0,
    "error":{"message":"Task failed.","type":"task_failed","param":"","code":"task_failed"}
  }
}
```

<Warning>
  조회가 HTTP `200`이어도 `data.status=failed`일 수 있습니다. `data.status`로 판단하며 실패 작업은 `cost=0`입니다.
</Warning>

## 가격 카탈로그

```http theme={null}
GET https://api.apimart.ai/api/pricing/models/all
```

`GET /api/pricing/models/all`을 읽고 `data.models.video`에서 `id`로 찾습니다. 표시는 예상가이며 최종 금액은 작업의 `data.cost`입니다.

### 출력 비디오 가격

```json theme={null}
{
  "fixed_prices":{
    "unit":"usd_per_second",
    "dimension":"resolution",
    "items":[
      {"key":"480P","original_price":0.05,"after_discount":0.04},
      {"key":"720P","original_price":0.07,"after_discount":0.056}
    ]
  }
}
```

* 가격 키는 대문자 `480P/720P/1080P`, 요청 값은 소문자입니다. 조회 시 정규화하세요.
* `default`는 호환 메타데이터이며 선택 가능한 해상도가 아닙니다.
* `after_discount`를 직접 사용하고 할인을 다시 적용하지 마세요.

### 입력 소재 가격

```json theme={null}
{"unit":"usd_per_image","original_price":0.002,"after_discount":0.0016}
```

```json theme={null}
{"unit":"usd_per_second","original_price":0.01,"after_discount":0.008}
```

비디오 입력 가격은 스칼라 객체입니다. `items`, `billing_mode`, `max_billable_seconds`를 요구하지 마세요. 1.5에는 입력 비디오 가격이 없습니다.

### 예상 공식

```text theme={null}
생성 예상 = 출력 초당 가격 × duration + 이미지 가격 × 개수
편집 예상 = 720P 출력 초당 가격 × 원본 초 + 입력 가격 × 원본 초
```

사용자별 가격과 서버 반올림으로 예상액이 달라질 수 있습니다. 최종 금액은 항상 `data.cost`입니다.

## 프런트엔드 규칙

### 모델 전환

* Base는 `480p/720p`, 1.5는 `1080p`도 표시.
* 1.5 `1080p`에서 Base로 전환 시 `480p`로 복귀.
* 비디오 편집은 `grok-imagine-video`로 고정.

### 모드 전환

| 모드     | 표시 컨트롤                                               | 제출 필드                           | 반드시 지울 필드                                     |
| ------ | ---------------------------------------------------- | ------------------------------- | --------------------------------------------- |
| 생성     | `prompt/duration/resolution/aspect_ratio/nsfw_check` | 생성 필드                           | `image_urls/video`                            |
| 참조 이미지 | 생성 필드 + `image_urls`                                 | 생성 필드 + `image_urls`            | `video`                                       |
| 비디오 편집 | `prompt/video/nsfw_check`                            | `model/prompt/video/nsfw_check` | `duration/resolution/aspect_ratio/image_urls` |

`nsfw_check`는 모든 모드에서 선택 사항입니다. 검토를 켜면 `true`, 끄면 생략하거나 `false`를 보냅니다.

다음 중 하나라도 해당하면 실행 버튼을 비활성화합니다.

* 텍스트 모드는 `image_urls`와 `video` 생략.
* 참조 모드는 `image_urls` 전송, `video` 생략.
* 편집 모드는 생성 전용 필드를 삭제.
* 프롬프트, 길이, 해상도, URL 오류, 업로드 중 또는 중복 제출 시 비활성화.
* 프롬프트 8000 Unicode 이하, 길이는 1\~15 정수.
* 공개 HTTPS URL만 사용하고 빈 `image_urls` 생략.

## 주요 오류

| HTTP / 상태     | 원인                   | 처리               |
| ------------- | -------------------- | ---------------- |
| `400`         | 매개변수, 프롬프트 또는 열거값 오류 | 메시지와 필드 표시       |
| `401`         | API Key 없음/오류        | 재시도하지 말고 서버 확인   |
| `402`         | 잔액 부족                | 충전 안내            |
| `403`         | 모델 권한 없음             | 자동 재시도 안 함       |
| `409`         | 멱등 충돌 또는 처리 중        | 원래 Key 유지 후 재시도  |
| `429`         | 요청 제한                | `Retry-After` 준수 |
| `500/502/503` | 일시 장애                | 원래 Key로 제한된 재시도  |
| `failed`      | 비동기 작업 실패            | 조회 중지, 비용 0      |

## 프런트엔드 확인

* API Key는 백엔드 또는 BFF에만 저장.
* 공식 모델과 `grok-imagine-1.5-video-ext`를 섞지 않음.
* 프롬프트 8000 Unicode 이하, 길이는 1\~15 정수.
* 공개 HTTPS URL만 사용하고 빈 `image_urls` 생략.
* 편집은 Base에서 `model/prompt/video`와 선택적 `nsfw_check`만 전송합니다.
* 제출 시 `data[0].task_id`, 종단은 `data.status`로 확인.
* `result.videos[].url[]`과 `expires_at` 사용.
* 카탈로그를 표시하고 최종 금액은 `data.cost` 사용.
