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

# Get Video Task 상태

> Query video generation task status and results

> [!NOTE]
>
> **중국 본토 사용자 안내:** 중국 본토 사용자는 `https://toapis.cn` 를 API 엔드포인트(Base URL)로 사용해 주세요. 본 문서의 예시에서 `https://toapis.com` 을 `https://toapis.cn` 로 바꿔 주세요.

* Query async video generation task execution status and results
* Real-time status updates and progress tracking
* Get generated videos when task completes
* Multi-language support (zh/en/ko/ja)

All video generation tasks are executed asynchronously. After submitting a task, you need to query the status and results via the query endpoint.

> [!NOTE]
>
> [소재 심사](https://docs.toapis.com/docs/ko/api-reference/videos/seedance-2/generation.md)가 필요한 Seedance 동영상 작업도 이 API로 조회합니다. `queued`에는 소재 준비와 심사 대기가 포함될 수 있으며, 작업 접수가 생성 시작을 뜻하지는 않습니다. 준비 기한은 기본 라운드당 20분이며 이후 동영상 생성 시간은 별도입니다. 실패 시 `error.message`를 확인하세요.

일반 이미지와 동영상 작업은 `GET /v1/tasks/{task_id}`로도 조회할 수 있으며 `usage`와 `billing`의 정의는 같습니다. 이 페이지는 상단에 표시된 생성 작업 조회 경로의 응답을 설명합니다.

예시는 필드 구조를 보여 주며 모델의 현재 가격이나 고정 과금 방식을 나타내지 않습니다. 실제 작업에서 반환된 필드와 금액을 확인하세요.

## Seedance 원본 URL과 대체 URL

원본 URL 전달이 활성화된 Seedance 작업에서 `result.data[].url`은 공급자의 원본 동영상 URL을 유지합니다. `url`을 우선 사용하고 접근할 수 없을 때만 같은 결과 항목의 `fallback_url`로 전환하세요. 플랫폼은 클라이언트 지역에 따라 URL을 자동 전환하지 않습니다.

대체 필드는 선택 사항이며 사본을 사용할 수 있을 때만 반환됩니다. 원본 URL 전달이 비활성화되었거나 사본을 사용할 수 없거나 이전 작업에 사본이 없으면 생략될 수 있습니다. 생략은 생성 실패를 의미하지 않습니다. 마지막 프레임도 `last_frame_url`을 우선 사용하고 접근할 수 없을 때만 `fallback_last_frame_url`을 사용하세요. 대체 URL은 원본 URL의 유효 기간을 연장하지 않습니다. 장기 보관이 필요하면 즉시 다운로드하세요.

## Authorizations

**Authorization** `string` *required*

All endpoints require Bearer Token authentication

Get your API Key:

Visit the [API Key Management Page](https://toapis.com/console/token) to get your API Key

Add it to the request header:

```
Authorization: Bearer YOUR_API_KEY
```

## Path 파라미터

**task\_id** `string` *required*

Task ID returned by the video generation API

```bash cURL theme={null}
curl --request GET \
  --url 'https://toapis.com/v1/videos/generations/task_01K9S419324DREZFBWNSVXYR6H' \
  --header 'Authorization: Bearer <token>'
```

```python Python theme={null}
import requests
import time

API_BASE = 'https://toapis.com'
API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx'

headers = {
    'Authorization': f'Bearer {API_KEY}'
}

def get_video_status(task_id):
    response = requests.get(f'{API_BASE}/v1/videos/generations/{task_id}', headers=headers)
    return response.json()

def wait_for_video(task_id, max_attempts=60, interval=10):
    for _ in range(max_attempts):
        result = get_video_status(task_id)
        status = result.get('status')
        progress = result.get('progress', 0)

        print(f"Status: {status}, Progress: {progress}%")

        if status == 'completed':
            return result
        elif status == 'failed':
            raise Exception(f"Task failed: {result}")

        time.sleep(interval)

    raise Exception("Task timeout")

# Usage example
task_id = "task_01K9S419324DREZFBWNSVXYR6H"
result = wait_for_video(task_id)
print(f"Video URL: {result['result']['data'][0]['url']}")
```

```javascript JavaScript theme={null}
const API_BASE = 'https://toapis.com';
const API_KEY = 'sk-xxxxxxxxxxxxxxxxxxxxxx';

async function getVideoStatus(taskId) {
  const response = await fetch(`${API_BASE}/v1/videos/generations/${taskId}`, {
    headers: {
      'Authorization': `Bearer ${API_KEY}`
    }
  });
  return response.json();
}

async function waitForVideo(taskId, maxAttempts = 60, interval = 10000) {
  for (let i = 0; i < maxAttempts; i++) {
    const result = await getVideoStatus(taskId);
    const status = result.status;
    const progress = result.progress || 0;

    console.log(`Status: ${status}, Progress: ${progress}%`);

    if (status === 'completed') {
      return result;
    } else if (status === 'failed') {
      throw new Error(`Task failed: ${JSON.stringify(result)}`);
    }

    await new Promise(r => setTimeout(r, interval));
  }

  throw new Error('Task timeout');
}

// Usage example
const taskId = 'task_01K9S419324DREZFBWNSVXYR6H';
waitForVideo(taskId).then(result => {
  console.log('Video URL:', result.result.data[0].url);
  console.log('Format:', result.result.data[0].format);
});
```

```go Go theme={null}
package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "net/http"
    "time"
)

func getVideoStatus(taskId string) (map[string]interface{}, error) {
    url := fmt.Sprintf("https://toapis.com/v1/videos/generations/%s", taskId)

    req, _ := http.NewRequest("GET", url, nil)
    req.Header.Set("Authorization", "Bearer <token>")

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
        return nil, err
    }
    defer resp.Body.Close()

    body, _ := ioutil.ReadAll(resp.Body)

    var result map[string]interface{}
    json.Unmarshal(body, &result)

    return result, nil
}

func main() {
    taskId := "task_01K9S419324DREZFBWNSVXYR6H"

    for i := 0; i < 60; i++ {
        result, _ := getVideoStatus(taskId)
        status := result["status"].(string)
        progress := int(result["progress"].(float64))

        fmt.Printf("Status: %s, Progress: %d%%\n", status, progress)

        if status == "completed" {
            fmt.Println("Video generation completed!")
            resultData := result["result"].(map[string]interface{})
            dataArray := resultData["data"].([]interface{})
            videoData := dataArray[0].(map[string]interface{})
            fmt.Println("Video URL:", videoData["url"])
            break
        }

        time.Sleep(10 * time.Second)
    }
}
```

```json 200 - Queued theme={null}
{
  "id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
  "object": "generation.task",
  "model": "sora-2",
  "status": "queued",
  "progress": 0,
  "created_at": 1768380222
}
```

```json 200 - In Progress theme={null}
{
  "id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
  "object": "generation.task",
  "model": "sora-2",
  "status": "in_progress",
  "progress": 65,
  "created_at": 1768380222
}
```

```json 200 - Completed theme={null}
{
  "id": "tsk_vid_01KRDG4S50XXXXXXXXXXXXXXX",
  "object": "generation.task",
  "model": "seedance-2",
  "status": "completed",
  "progress": 100,
  "created_at": 1778569600,
  "finished_at": 1778569900,
  "completed_at": 1778569900,
  "expires_at": 1778656300,
  "result": {
    "type": "video",
    "data": [
      {
        "url": "https://files.toapis.com/videos/tsk_vid_01KRDG4S50XXXXXXXXXXXXXXX/********_********.mp4",
        "format": "mp4"
      }
    ]
  },
  "billing": {
    "status": "settled",
    "credits": "100",
    "cost_usd": "0.5"
  }
}
```

```json 200 - Failed theme={null}
{
  "id": "video_7497f4d5-3a88-44c7-923a-967fa7d941a0",
  "object": "generation.task",
  "model": "sora-2",
  "status": "failed",
  "progress": 0,
  "created_at": 1768380222,
  "error": {
    "code": "generation_failed",
    "message": "Generation failed: Content violates the content policy"
  }
}
```

```json 404 theme={null}
{
  "error": {
    "code": 404,
    "message": "Task not found",
    "type": "not_found_error"
  }
}
```

```json 401 theme={null}
{
  "error": {
    "code": 401,
    "message": "Authentication failed, please check your API key",
    "type": "authentication_error"
  }
}
```

```json 200 - Seedance theme={null}
{
  "id": "task_seedance_example",
  "object": "generation.task",
  "model": "seedance-2-global",
  "client_business_id": "order_123",
  "status": "completed",
  "progress": 100,
  "created_at": 1792400000,
  "updated_at": 1792400061,
  "finished_at": 1792400060,
  "completed_at": 1792400060,
  "expires_at": 1792486460,
  "result": {
    "type": "video",
    "data": [
      {
        "url": "https://cdn.example/result.mp4",
        "fallback_url": "https://files.toapis.com/videos/task_seedance_example/result.mp4",
        "format": "mp4",
        "last_frame_url": "https://cdn.example/last-frame.jpg",
        "fallback_last_frame_url": "https://files.toapis.com/videos/task_seedance_example/last-frame.jpg"
      }
    ]
  },
  "usage": {
    "charge_type": "per_token",
    "billed_tokens": 87300,
    "completion_tokens": 87300,
    "total_tokens": 87300
  },
  "billing": {
    "status": "settled",
    "credits": "87.3",
    "cost_usd": "0.4365"
  },
  "generation": {
    "duration": 5,
    "resolution": "720p",
    "ratio": "16:9",
    "generate_audio": true,
    "usage": {
      "completion_tokens": 87300,
      "total_tokens": 87300
    }
  }
}
```

## 응답

**id** `string`

Unique task identifier

**client\_business\_id** `string`

선택적 고객 업무 ID입니다. 작업 생성 시 `client_business_id`를 전달한 경우에만 반환합니다.

**object** `string`

Object type, always `generation.task`

**status** `string`

Task status

* `queued` - Queued for processing
* `in_progress` - Processing
* `completed` - Successfully completed
* `failed` - Failed

**progress** `integer`

Task progress percentage (0-100)

**model** `string`

Video generation model used

**updated\_at** `integer`

선택적 플랫폼 작업 갱신 시각, Unix 타임스탬프입니다. 현재 Seedance Global에 반환합니다. `generation.updated_at`는 상위 공급자의 갱신 시각입니다.

**created\_at** `integer`

Task creation time (Unix timestamp)

**finished\_at** `integer`

작업 종료 시각, Unix 타임스탬프입니다. 이 조회 경로에서는 성공 또는 실패한 작업에 종료 시각이 저장된 경우 반환합니다.

**completed\_at** `integer`

Task completion time (Unix timestamp, only returned when completed)

**expires\_at** `integer`

Video URL expiration time (Unix timestamp, only returned on completion)

**result** `object`

Task result (only returned on success)

**Properties**

**type** `string`

Result type, always `video`

**data** `array`

Video data array

**Array item**

**url** `string`

기본 동영상 URL. 원본 URL 전달이 활성화된 Seedance 작업은 공급자의 원본 URL을 유지합니다. 이 URL을 우선 사용하세요.

**fallback\_url** `string`

사본을 사용할 수 있을 때만 반환되는 선택적 대체 동영상 URL. 기본 URL에 접근할 수 없을 때만 사용하며 `url`을 대체하지 않습니다.

**format** `string`

Video format (for example `mp4`)

**last\_frame\_url** `string`

생성된 동영상의 마지막 프레임 이미지 URL입니다. `return_last_frame: true`로 생성했고 모델이 프레임을 반환한 경우에만 포함됩니다.

**fallback\_last\_frame\_url** `string`

프레임 사본을 사용할 수 있을 때 반환되는 선택적 대체 URL. `last_frame_url`에 접근할 수 없을 때만 사용하세요.

**generation** `object`

선택적 Seedance 생성 메타데이터입니다. 저장되어 있고 공개 가능한 필드만 반환하며 기본값을 채우지 않습니다. 생성 매개변수이며 최상위 `usage`의 과금 수량을 대체하지 않습니다.

| 필드 | 타입 | 설명 |
| - | - | - |
| `created_at`, `updated_at` | number | 상위 공급자 작업 생성 및 갱신 시각, Unix 타임스탬프. 최상위 플랫폼 시각과 구분됩니다 |
| `seed` | number | 난수 시드 |
| `resolution` | string | 해상도 |
| `ratio` | string | 화면 비율 |
| `duration` | number | 생성 길이, 초 단위 |
| `framespersecond` | number | 프레임 레이트, 초당 프레임 수 |
| `service_tier` | string | 서비스 등급 |
| `execution_expires_after` | number | 실행 유효 기간, 초 단위 |
| `generate_audio` | boolean | 오디오 생성 여부 |
| `draft` | boolean | 초안 여부 |
| `priority` | number | 스케줄링 우선순위 |
| `output_format` | string | 출력 형식 |

`generation.usage`는 기존 호환 필드이며 `completion_tokens`와 `total_tokens`를 포함할 수 있습니다. 누락되거나 최종 과금 수량과 다를 수 있습니다. 최상위 `usage`와 합산하지 말고 과금 수량은 최상위 `usage`를 사용하세요.

**usage** `object`

선택적 과금 수량, 동영상 토큰 내역, 도구 사용 횟수입니다. 단위와 생략 조건은 [작업 사용량 필드](https://docs.toapis.com/docs/ko/api-reference/account/pricing.md)를 참고하세요.

| 필드 | 타입 | 값 |
| - | - | - |
| `charge_type` | string | 과금 방식: `per_request`, `per_second`, `per_token` |
| `requests` | integer | 과금 요청 횟수. `per_request`일 때 반환합니다. Midjourney 동영상의 유효한 `batch_size`가 반영됩니다 |
| `billed_tokens` | integer | 가격 계산에 사용한 토큰 수. `per_token`일 때 반환합니다 |
| `output_seconds` | integer | 과금 대상 출력 동영상 길이, 정수 초 단위. `per_second`일 때 반환합니다 |
| `input_seconds` | integer | 과금 대상 입력 동영상 길이, 정수 초 단위. 0이면 생략합니다 |
| `input_images` | integer | 무료 한도를 제외하고 과금 대상이 된 입력 이미지 수. 0이면 생략합니다 |
| `input_tokens`, `output_tokens`, `prompt_tokens`, `completion_tokens`, `total_tokens` | integer | 동영상 모델이 보고한 토큰 수를 그대로 반환합니다. 토큰 과금 정산 시 `total_tokens`가 채워질 수 있습니다 |
| `tool_usage` | object | 도구 사용 횟수: `web_search`, `image_search`, `grounding_queries`. 사용한 경우에만 반환합니다 |

`charge_type`부터 `input_images`까지는 과금 수량이며 `billing.status=settled`와 함께만 반환합니다. 고정 가격 동영상은 제출 시 확인된 수량을, 실제 길이나 토큰으로 정산하는 동영상은 최종 정산 수량을 반환합니다. 반환하지 않는 필드는 0으로 채우지 않고 생략합니다.

**billing** `object`

선택적인 플랫폼 청구 상태와 확정 금액입니다. 과금 상태는 생성 상태와 별개이므로 `completed`여도 정산이 완료되었다고 단정할 수 없습니다. 객체가 없다고 해서 무료인 것은 아닙니다. [가격 및 실제 청구 금액](https://docs.toapis.com/docs/ko/api-reference/account/pricing.md)을 참고하세요.

**속성**

**status** `string`

`pending`은 생성 중이거나 정산 대기 중이거나 환불이 아직 확인되지 않은 상태이며 금액을 생략합니다. `settled`는 제출 시 한 번에 과금되는 고정 가격 동영상을 포함해 최종 청구 금액이 확정된 상태이며 실제 금액을 반환합니다. `refunded`는 환불되었거나 실패 후 순 청구 금액이 없는 것으로 확인된 상태이며 두 금액 모두 `"0"`입니다.

**credits** `string`

실제로 청구된 ToAPIs 크레딧을 십진수 문자열로 반환합니다. `settled` 또는 `refunded`일 때만 반환합니다.

**cost\_usd** `string`

같은 청구의 USD 금액을 십진수 문자열로 반환합니다. `credits`와 같은 조건에서 반환하며 할인과 배율을 포함하고 공급자 원가가 아닙니다.

Task Webhook의 `data.billing`도 같은 확인 조건과 값을 사용합니다.

**error** `object`

오류 information (only returned on failure)

오류 코드와 메시지는 일반적으로 문자열입니다. Seedance Global은 `error.code`와 `error.message`에 숫자나 `null`을 포함한 원래 공급자의 JSON 값을 유지합니다. 공급자가 제공하지 않은 필드를 플랫폼 기본값으로 채우지 않습니다.

**Properties**

**code** `any`

오류 code

**message** `any`

오류 description

## Task 상태 Reference

| 상태 | 설명 | Is Final | Recommended Action |
| - | - | - | - |
| `queued` | Task submitted, waiting in queue | ❌ | Wait 5-10 seconds, then query again |
| `in_progress` | Task is processing | ❌ | Wait 10-15 seconds, then query again |
| `completed` | Task completed successfully | ✅ | Get video from `result.data[0].url` |
| `failed` | Task processing failed | ✅ | Check error info |

## Polling Strategy

```
Initial wait: 5 seconds
Polling interval: 10 seconds
Max wait: 600 seconds (10 minutes)
Typical time: 1-5 minutes
```

### Python Polling Example

```python theme={null}
import time
import random
import requests

def poll_video_task(task_id, api_key, max_wait=600):
    """Poll video generation task until completion or timeout"""
    start_time = time.time()
    interval = 10  # 10 second interval

    # Initial 5 second wait
    time.sleep(5)

    while time.time() - start_time < max_wait:
        response = requests.get(
            f'https://toapis.com/v1/videos/generations/{task_id}',
            headers={'Authorization': f'Bearer {api_key}'}
        )
        if response.status_code == 429:
            retry_after = int(response.headers.get('Retry-After', interval))
            time.sleep(retry_after + random.uniform(0, 1))
            interval = min(interval * 2, 120)
            continue
        response.raise_for_status()
        data = response.json()

        print(f"Status: {data['status']}, Progress: {data.get('progress', 0)}%")

        if data['status'] == 'completed':
            return {
                'url': data['result']['data'][0]['url'],
                'format': data['result']['data'][0].get('format'),
                'expires_at': data.get('expires_at')
            }
        elif data['status'] == 'failed':
            raise Exception(f"Generation failed: {data['error']['message']}")

        time.sleep(interval + random.uniform(0, 1))

    raise TimeoutError("Task timeout")
```

## Resource Expiration

> [!WARNING]
>
> Generated video URLs are valid for **24 hours**
>
> * Please download and save videos within the validity period
> * `expires_at` field indicates video expiration time (Unix timestamp)
> * Expired videos cannot be accessed; to regenerate, submit a new task
> * Thumbnails expire simultaneously with videos

## 오류와 실패 원인

요청 오류, 작업 실패의 구체적인 원인과 복구 방법은 [오류 코드 빠른 참조](https://docs.toapis.com/docs/ko/api-reference/errors.md) 를 확인하세요. 조회 성공 후에도 작업 상태를 확인하고 HTTP 상태와 비즈니스 코드를 구분하세요.

## Performance Tips

> [!NOTE]
>
> Video generation takes longer, recommendations:
>
> 1. **ToAPIs Task Webhook**: [Webhook](https://docs.toapis.com/docs/ko/api-reference/webhooks/task-webhooks.md)을 기본으로, 조회를 대체 경로로 사용
> 2. **조회 간격**: 5\~10초 이상과 지터. 429는 `Retry-After`를 읽고 지수 백오프
> 3. **Set Timeout**: Long videos may take 5-10 minutes, set reasonable timeout
> 4. **Download Promptly**: Videos expire after 24 hours, save to your storage immediately

[비동기 작업 속도 제한](https://docs.toapis.com/docs/ko/api-reference/rate-limits/async-tasks.md)을 참조하세요. 배치 조회는 최대 100개입니다.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.