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

# Как узнать фактическую стоимость видео Seedance по task_id?

> В логах для одного видео отображаются две записи списания и одна квота в деталях задачи. Ниже объясняется, как соотносятся эти три числа и как программно получить итоговую стоимость видео по task_id.

## Краткий ответ

**Запросите API задачи по `task_id`; возвращаемое значение `quota` — это общая стоимость видео.** Две записи журнала (предварительное списание + расчёт) в сумме дают эту стоимость, а значение `quota` в подробном представлении «Асинхронные задачи» — то же самое число.

```bash theme={null}
curl --compressed -s "https://api.apiyi.com/api/task/self?p=1&page_size=1&task_id=<your task_id>" \
  -H "Authorization: $APIYI_SYS_TOKEN" | jq '.data.items[0] | {task_id, status, quota, submit_time, finish_time}'
```

`quota ÷ 500,000 = USD`. Выполните аутентификацию с помощью **системного token** (не ключа API `sk-`); информацию о его получении см. в [API запросов журналов](/ru/api-capabilities/log-query).

Не пытайтесь сопоставлять записи журнала по одной через API запросов журналов: ни одна из записей не содержит `task_id`, а запись расчёта имеет пустое значение `request_id`.

## Как связаны три числа

Видео Seedance тарифицируются по схеме «предварительное списание при отправке, расчёт разницы по завершении», поэтому для одного видео создаются две записи журнала, тогда как API задачи и представление сведений о задаче показывают одно значение `quota`:

| Где                                         | Значение          | Описание                                                                                                                                                                                                                                            |
| ------------------------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Запись журнала 1 (предварительное списание) | например, 224,999 | Рассчитывается на основе параметров запроса и списывается при отправке. `completion_tokens` равно 0, `request_id` присутствует                                                                                                                      |
| Запись журнала 2 (расчёт)                   | например, 702,613 | Итог пересчитывается на основе фактических tokens по завершении, и **записывается только разница** (положительное значение = дополнительное списание, отрицательное = возврат). `completion_tokens` — фактическое использование, `request_id` пусто |
| API задачи / сведения о задаче `quota`      | например, 927,612 | **Сумма двух значений = итоговая стоимость** = фактические tokens × коэффициент модели × коэффициент группы                                                                                                                                         |

Расчёт также может быть возвратом: для быстрой задачи преобразования текста в видео 480p длительностью 4 секунды было предварительно списано 144,000, использовано 40,594 tokens × 18.5 × 0.18 = 135,179, поэтому в записи расчёта указано −8,821 (возврат \$0.02), а значение API задачи `quota` равно 135,179.

Первый набор чисел получен из реальной задачи преобразования изображения в видео 2.0 с эталонным видео: 368,100 tokens × 14 (тарифный уровень для входного видео) × 0.18 (коэффициент группы) = 927,612, то есть \$1.86. Поле `other` записи расчёта содержит `final_quota` = 927,612, `original_quota` = 224,999 и `adjustment_quota` = 702,613, поэтому все три значения видны в одной записи.

## Определение фактической стоимости по статусу

| `status`                    | Что означает `quota`                                                   | Фактическая стоимость видео                                                                                                                    |
| --------------------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `completed`                 | Итоговая сумма после расчёта                                           | = `quota`                                                                                                                                      |
| `submitted` / `in_progress` | Только предварительное списание при отправке                           | Дождитесь завершения                                                                                                                           |
| `failed`                    | **По-прежнему отображает предварительное списание; оно не обнуляется** | **0**. Предварительное списание полностью возвращается в виде отрицательной записи журнала `type=11`, поле `content` которой содержит task\_id |

Обратите внимание, что используются два разных набора терминов: эндпоинт запроса видео `/seedance/api/v3/.../tasks/{id}` сообщает об успехе как `succeeded`, тогда как API задач `/api/task/self` сообщает о нём как `completed`; не копируйте условие из кода опроса.

<Warning>
  Суммирование `quota` по неуспешным задачам учитывает их предварительное списание как расход. При программной сверке фильтруйте по `status`; если вместо этого вы выполняете сверку через API запроса журналов, **получайте и `type=2`, и `type=11`**, где последнее обозначает записи возврата с отрицательным `quota`.
</Warning>

## Написание параметров (в отличие от Log Query API)

Параметры пагинации API задач используют **snake\_case `page_size`**, а номер страницы **`p` начинается с 1**; Log Query API использует camelCase `pageSize`, где `p` начинается с 0. Ошибка не вызывает ошибку, вы просто получите страницу по умолчанию.

Проверенные фильтры:

| Параметр                            | Описание                                                         |
| ----------------------------------- | ---------------------------------------------------------------- |
| `task_id`                           | Получить ровно одну задачу                                       |
| `model_name`                        | Фильтрация по модели, например `doubao-seedance-2-0-fast-260128` |
| `start_timestamp` / `end_timestamp` | Unix-секунды, фильтрация по времени отправки                     |
| `p` / `page_size`                   | Пагинация, `p` начинается с 1                                    |

Для пакетной сверки выполняйте выборку по временному окну; каждый элемент содержит `task_id`, `status`, `quota`, `submit_time`, `finish_time` и `model_name`:

```python theme={null}
import os, time, requests

BASE = "https://api.apiyi.com"
HEADERS = {"Authorization": os.environ["APIYI_SYS_TOKEN"], "Accept": "application/json"}

def video_cost(task_id: str):
    """Return (status, cost in USD). Failed tasks cost 0; in-progress tasks return None."""
    r = requests.get(f"{BASE}/api/task/self", headers=HEADERS, timeout=60,
                     params={"p": 1, "page_size": 1, "task_id": task_id})
    r.raise_for_status()
    items = r.json()["data"]["items"]
    if not items:
        return None, None
    task = items[0]
    status = task["status"]
    if status == "completed":
        return status, task["quota"] / 500_000
    if status == "failed":
        return status, 0.0
    return status, None          # submitted / in_progress: quota is only the pre-charge, do not book it yet

def list_tasks(start: int, end: int, page_size: int = 100):
    """Page through a submission-time window; p starts at 1, stop on an empty page."""
    p = 1
    while True:
        r = requests.get(f"{BASE}/api/task/self", headers=HEADERS, timeout=60,
                         params={"p": p, "page_size": page_size,
                                 "start_timestamp": start, "end_timestamp": end})
        r.raise_for_status()
        items = r.json()["data"]["items"]
        if not items:
            return
        yield from items
        p += 1
        time.sleep(1)
```

## Если необходимо вручную сверить данные в журналах

Три поля в строке записи о расчёте соответствуют API задач:

* Её временная метка (`created_at`) совпадает с `finish_time` задачи с точностью до 1 секунды
* Её `completion_tokens` совпадает с `usage.completion_tokens` задачи
* Её `other.final_quota` совпадает с `quota` задачи

`request_id` записи о предварительном списании совпадает с заголовком **`X-Shellapi-Request-Id`** ответа на отправку, поэтому запись можно найти с помощью `/api/log/self?request_id=…`. Обратите внимание: ответ также содержит заголовок `X-Request-Id`; это идентификатор запроса на стороне провайдера, который невозможно найти в журналах APIYI. Однако **записи о предварительном списании совпадают при отправке нескольких задач в одну и ту же секунду**, а запись о расчёте не содержит `request_id`, поэтому журналы подходят только для выборочной проверки отдельных задач. Для программной сверки используйте API задач.

## Часто задаваемые вопросы

<AccordionGroup>
  <Accordion title="Квота в сведениях о задаче отличается от суммы двух записей журнала?">
    Сначала проверьте статус задачи. Пока `submitted` / `in_progress`, `quota` представляет собой только предварительное списание, а второй записи журнала ещё нет; при `failed` `quota` всё ещё показывает предварительное списание, тогда как в журналах появилась отрицательная запись возврата, поэтому сумма двух записей равна 0. Для задач `completed` эти значения должны совпадать; если это не так, отправьте `task_id` в службу поддержки.
  </Accordion>

  <Accordion title="Почему в записи расчёта нет token и request_id?">
    Расчёт проводится системой после завершения задачи, вне пути запроса к шлюзу, поэтому в нём нет token, группы или `request_id`, а в консоли он помечен как «streaming». Это нормально.
  </Accordion>

  <Accordion title="Содержат ли задачи, отправленные через универсальные эндпоинты видео, task_id в журналах?">
    В `/v1/videos` и других универсальных эндпоинтах `content` записи предварительного списания включает `task ID: cgt-…`, однако запись расчёта по-прежнему его не содержит. Кроме того, эти эндпоинты пока не полностью передают параметр разрешения Seedance, поэтому всегда используйте документированный путь `/seedance/api/v3/contents/generations/tasks`; см. [API генерации видео](/ru/api-capabilities/seedance2/video-generation).
  </Accordion>

  <Accordion title="Может ли системный token просматривать задачи других аккаунтов?">
    `/api/task/self` возвращает только задачи аккаунта, которому принадлежит token. Системный token эквивалентен учётным данным аккаунта, поэтому защищайте его как пароль и не храните в репозиториях кода.
  </Accordion>
</AccordionGroup>

## Связанные документы

* [Seedance 2.0 / 2.5: просмотр списаний в журналах](/ru/api-capabilities/seedance2/overview)
* [API запросов журналов](/ru/api-capabilities/log-query)
* [Можно ли отменить задачу генерации видео Seedance после отправки?](/ru/faq/seedance-video-task-cancel)
* [Что такое механизм предварительного списания для вызовов API?](/ru/faq/pre-deduction-quota)
