> ## 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 Status

> Query video generation task status and results

> [!NOTE]
>
> **Note for users in mainland China:** Please use `https://toapis.cn` as the API endpoint (Base URL). Replace `https://toapis.com` with `https://toapis.cn` in the examples in this document.

* 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]
>
> Seedance video tasks that require [asset review](https://docs.toapis.com/docs/en/api-reference/videos/seedance-2/generation.md) use this same status endpoint. `queued` may include asset preparation and review; receiving a task does not mean video generation has started. Preparation defaults to 20 minutes per round, excluding subsequent video generation. Inspect `error.message` on failure.

Ordinary image and video tasks can also be queried with `GET /v1/tasks/{task_id}`, using the same `usage` and `billing` definitions. This page describes responses from the generation-task query path shown above.

Examples illustrate the fields, not current model prices or a fixed billing mode. Use the fields and amounts returned for the actual task.

## Seedance original and fallback URLs

For Seedance tasks with original URL delivery enabled, `result.data[].url` preserves the original upstream video URL. Use `url` first and switch to `fallback_url` on the same result item only if the primary URL cannot be accessed. The platform does not switch URLs automatically based on the client region.

Fallback fields are optional and are returned only when a copy is available. They may be omitted when original URL delivery is disabled, a copy is unavailable, or a historical task has no copy. Omission does not mean generation failed. For the last frame, use `last_frame_url` first and `fallback_last_frame_url` only if it cannot be accessed. A fallback does not extend the original URL validity period. Download promptly if you need long-term storage.

## 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 Parameters

**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
    }
  }
}
```

## Response

**id** `string`

Unique task identifier

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

Optional customer business ID, returned only when `client_business_id` was supplied at task creation.

**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`

Optional platform task update time as a Unix timestamp, currently returned for Seedance Global. `generation.updated_at` is the upstream update time.

**created\_at** `integer`

Task creation time (Unix timestamp)

**finished\_at** `integer`

Task finish time as a Unix timestamp. This query path returns it for successful or failed tasks when a finish time has been saved.

**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`

Primary video URL. Seedance tasks with original URL delivery enabled preserve the original upstream URL. Use this URL first.

**fallback\_url** `string`

Optional backup video URL, returned only when a copy is available. Use only if the primary URL cannot be accessed. It does not replace `url`.

**format** `string`

Video format (for example `mp4`)

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

URL of the generated video's last-frame image. Present only when the task was created with `return_last_frame: true` and the model returned a frame.

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

Optional backup last-frame URL, returned when a frame copy is available. Use only if `last_frame_url` cannot be accessed.

**generation** `object`

Optional Seedance generation metadata. Only saved, publicly available fields are returned; defaults are not filled in. These parameters describe generation and do not replace the billing quantities in top-level `usage`.

| Field | Type | Description |
| - | - | - |
| `created_at`, `updated_at` | number | Upstream task creation and update times, as Unix timestamps; distinct from platform timestamps at the top level |
| `seed` | number | Random seed |
| `resolution` | string | Resolution |
| `ratio` | string | Aspect ratio |
| `duration` | number | Generated duration in seconds |
| `framespersecond` | number | Frames per second |
| `service_tier` | string | Service tier |
| `execution_expires_after` | number | Execution validity period in seconds |
| `generate_audio` | boolean | Whether audio is generated |
| `draft` | boolean | Whether this is a draft |
| `priority` | number | Scheduling priority |
| `output_format` | string | Output format |

`generation.usage` is an existing compatibility field that may contain `completion_tokens` and `total_tokens`. It may be absent or differ from final billed quantities. Do not add it to top-level `usage`; use top-level `usage` for billing quantities.

**usage** `object`

Optional billing quantities, video-token details, and tool counts. See [Task usage fields](https://docs.toapis.com/docs/en/api-reference/account/pricing.md) for units and omission rules.

| Field | Type | Values |
| - | - | - |
| `charge_type` | string | Billing mode: `per_request`, `per_second`, or `per_token` |
| `requests` | integer | Billed request count, returned for `per_request`. The effective Midjourney video `batch_size` is counted |
| `billed_tokens` | integer | Tokens used for pricing, returned for `per_token` |
| `output_seconds` | integer | Billed output video duration in whole seconds, returned for `per_second` |
| `input_seconds` | integer | Billed input video duration in whole seconds; omitted when zero |
| `input_images` | integer | Billed input images after the free allowance; omitted when zero |
| `input_tokens`, `output_tokens`, `prompt_tokens`, `completion_tokens`, `total_tokens` | integer | Tokens reported by the video model, as provided; per-token settlement can fill `total_tokens` |
| `tool_usage` | object | Tool counts: `web_search`, `image_search`, `grounding_queries`, returned when used |

`charge_type` through `input_images` are billing quantities and are returned only together with `billing.status=settled`. Fixed-price videos return the quantities confirmed at submission; videos settled by actual duration or tokens return the final settled quantities. Fields that are not returned are omitted, not filled with zeros.

**billing** `object`

Optional platform billing status and confirmed charge. Billing status is independent of generation status; `completed` does not guarantee settlement. A missing object does not mean the task was free. See [Pricing and Actual Charges](https://docs.toapis.com/docs/en/api-reference/account/pricing.md).

**Properties**

**status** `string`

`pending`: generating, awaiting settlement, or refund not yet confirmed; amounts are omitted. `settled`: the final charge is confirmed, including fixed-price videos charged once at submission, and the actual amount is returned. `refunded`: refunded, or confirmed to have no net charge after failure; both amounts are `"0"`.

**credits** `string`

ToAPIs Credits actually charged, as a decimal string. Returned only for `settled` or `refunded`.

**cost\_usd** `string`

USD amount of the same charge, as a decimal string. Returned under the same conditions as `credits`; includes discounts and multipliers and is not the provider cost.

Task Webhook `data.billing` uses the same confirmation rules and values.

**error** `object`

Error information (only returned on failure)

Error codes and messages are normally strings. Seedance Global preserves the original upstream JSON values in `error.code` and `error.message`, including numbers or `null`. Missing upstream fields are not replaced with platform defaults.

**Properties**

**code** `any`

Error code

**message** `any`

Error description

## Task Status Reference

| Status | Description | 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

## Errors and failure reasons

See the [error reference](https://docs.toapis.com/docs/en/api-reference/errors.md) for request errors, task failures, specific causes, and recovery guidance. A successful query still requires checking task status; HTTP status is not a business error code.

## Performance Tips

> [!NOTE]
>
> Video generation takes longer, recommendations:
>
> 1. **Use the ToAPIs Task Webhook**: Prefer [Webhooks](https://docs.toapis.com/docs/en/api-reference/webhooks/task-webhooks.md) and keep polling as fallback
> 2. **Set a Reasonable Polling Interval**: At least 5–10 seconds with jitter; on 429, honor `Retry-After` and back off exponentially
> 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

See [Async task rate limits](https://docs.toapis.com/docs/en/api-reference/rate-limits/async-tasks.md). A batch query accepts at most 100 task IDs.


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