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

# Lấy trạng thái video

> Truy xuất trạng thái và kết quả của một tác vụ tạo video

## Tham số đường dẫn

<ParamField path="id" type="string" required>
  ID tác vụ trả về từ yêu cầu tạo video. Xem `id` và `task_id` là cùng một định danh không đồng bộ (async).
</ParamField>

<Info>
  Nếu phản hồi create trả về `poll_url`, hãy gọi đúng URL đó. Khi nó trỏ tới `/v1/tasks/{id}`, hãy coi đó là endpoint trạng thái cố định chuẩn.

  Nếu tác vụ không còn tồn tại hoặc không còn có trong bản ghi tác vụ công khai, TokenLab trả về `async_task_not_found` với thông báo `Task not found or no longer available.`
</Info>

## Phản hồi

<ResponseField name="id" type="string">
  Định danh tác vụ async chuẩn.
</ResponseField>

<ResponseField name="task_id" type="string">
  Bí danh định danh tác vụ async.
</ResponseField>

<ResponseField name="poll_url" type="string">
  URL ưu tiên để thăm dò khi phản hồi tạo cung cấp.
</ResponseField>

<ResponseField name="billing_transaction_id" type="string">
  ID giao dịch billing của TokenLab khi việc settlement đã hoàn tất. Đây là mã giao dịch dùng cho dashboard/đối soát và tách biệt với `id` / `task_id` bất đồng bộ.
</ResponseField>

<ResponseField name="status" type="string">
  Trạng thái tác vụ: `pending`, `processing`, `completed`, `failed`.
</ResponseField>

<ResponseField name="progress" type="number">
  Giá trị tiến độ tùy chọn. Chỉ được trả về khi có giá trị tiến độ thực; hãy dùng `status` để xác định khi tác vụ hoàn tất.
</ResponseField>

<ResponseField name="video_url" type="string">
  URL của video đã tạo (khi hoàn thành).
</ResponseField>

<ResponseField name="video" type="object">
  Payload video đơn với `url`, `duration`, `width`, và `height` khi có.
</ResponseField>

<ResponseField name="videos" type="array">
  Nhiều payload video khi tác vụ tạo trả về hơn một kết quả.
</ResponseField>

<ResponseField name="error" type="string">
  Thông báo lỗi (nếu thất bại).
</ResponseField>

<ResponseField name="created" type="integer">
  Dấu thời gian tạo.
</ResponseField>

<ResponseField name="updated" type="integer">
  Dấu thời gian cập nhật cuối cùng.
</ResponseField>

<ResponseField name="model" type="string">
  Mô hình được sử dụng cho tác vụ.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl "https://api.tokenlab.sh/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" \
    -H "Authorization: Bearer sk-your-api-key"
  ```

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

  task_id = "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

  while True:
      response = requests.get(
          f"https://api.tokenlab.sh/v1/tasks/{task_id}",
          headers={"Authorization": "Bearer sk-your-api-key"}
      )

      data = response.json()
      print(f"Status: {data['status']}")

      if data["status"] == "completed":
          print(f"Video URL: {data['video_url']}")
          break
      elif data["status"] == "failed":
          print(f"Error: {data['error']}")
          break

      time.sleep(5)  # Poll every 5 seconds
  ```

  ```javascript JavaScript theme={null}
  const taskId = 'ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

  async function pollForVideo() {
    while (true) {
      const response = await fetch(
        `https://api.tokenlab.sh/v1/tasks/${taskId}`,
        { headers: { 'Authorization': 'Bearer sk-your-api-key' } }
      );

      const data = await response.json();
      console.log(`Status: ${data.status}`);

      if (data.status === 'completed') {
        console.log(`Video URL: ${data.video_url}`);
        return data.video_url;
      } else if (data.status === 'failed') {
        throw new Error(data.error);
      }

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

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

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

  func main() {
      taskID := "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

      for {
          req, _ := http.NewRequest("GET",
              fmt.Sprintf("https://api.tokenlab.sh/v1/tasks/%s", taskID), nil)
          req.Header.Set("Authorization", "Bearer sk-your-api-key")

          client := &http.Client{}
          resp, _ := client.Do(req)

          var result map[string]interface{}
          json.NewDecoder(resp.Body).Decode(&result)
          resp.Body.Close()

          fmt.Printf("Status: %s\n", result["status"])

          if result["status"] == "completed" {
              fmt.Printf("Video URL: %s\n", result["video_url"])
              break
          } else if result["status"] == "failed" {
              fmt.Printf("Error: %s\n", result["error"])
              break
          }

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

  ```php PHP theme={null}
  <?php
  $taskId = 'ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

  while (true) {
      $ch = curl_init("https://api.tokenlab.sh/v1/tasks/{$taskId}");

      curl_setopt_array($ch, [
          CURLOPT_RETURNTRANSFER => true,
          CURLOPT_HTTPHEADER => [
              'Authorization: Bearer sk-your-api-key'
          ]
      ]);

      $response = curl_exec($ch);
      curl_close($ch);

      $data = json_decode($response, true);
      echo "Status: {$data['status']}\n";

      if ($data['status'] === 'completed') {
          echo "Video URL: {$data['video_url']}\n";
          break;
      } elseif ($data['status'] === 'failed') {
          echo "Error: {$data['error']}\n";
          break;
      }

      sleep(5);
  }
  ```
</RequestExample>

<ResponseExample>
  ```json Response (pending) theme={null}
  {
    "id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "task_id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "poll_url": "/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "status": "pending",
    "model": "veo3.1",
    "created": 1706000000,
    "updated": 1706000000
  }
  ```

  ```json Response (processing) theme={null}
  {
    "id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "task_id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "poll_url": "/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "status": "processing",
    "model": "veo3.1",
    "created": 1706000000,
    "updated": 1706000030
  }
  ```

  ```json Response (completed) theme={null}
  {
    "id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "task_id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "poll_url": "/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "billing_transaction_id": "cmo164zyc0s48jpgegi80vqv4",
    "status": "completed",
    "video_url": "https://assets.tokenlab.sh/videos/abc123.mp4",
    "model": "veo3.1",
    "created": 1706000000,
    "updated": 1706000060
  }
  ```

  ```json Response (failed) theme={null}
  {
    "id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "task_id": "ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "poll_url": "/v1/tasks/ldtask_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
    "status": "failed",
    "error": "Content policy violation",
    "model": "veo3.1",
    "created": 1706000000,
    "updated": 1706000060
  }
  ```
</ResponseExample>

## Thực hành tốt nhất khi thăm dò

* Thăm dò (poll) mỗi 5-10 giây
* Triển khai exponential backoff cho các tác vụ chạy lâu
* Đặt thời gian chờ tối đa (ví dụ: 10 phút)
* Xử lý trạng thái `failed` một cách phù hợp

```python theme={null}
import time

def wait_for_video(task_id, max_wait=600, interval=5):
    """Wait for video with timeout."""
    start = time.time()

    while time.time() - start < max_wait:
        response = requests.get(
            f"https://api.tokenlab.sh/v1/tasks/{task_id}",
            headers={"Authorization": "Bearer sk-your-api-key"}
        )
        data = response.json()

        if data["status"] == "completed":
            return data["video_url"]
        elif data["status"] == "failed":
            raise Exception(data.get("error", "Video generation failed"))

        time.sleep(interval)

    raise TimeoutError("Video generation timed out")
```
