
Сколько стоит ежедневное видео AI? Бюджет на 30 дней
Рассчитайте 30-дневный бюджет на вертикальное AI-видео: повторы, лимиты бесплатных кредитов, безопасный опрос API, хранение и ручная проверка.
Для протестированной конфигурации ежедневное видео стоит $2.52 за генерацию на 30 дней. Каждая попытка — пятисекундный клип 480p, 9:16 с seedance-2.0-mini. Один тест обошёлся 84 кредитами reAPI, или $0.084, завершился за 107.2 секунды и вернул один URL видео.[6]
Это простой ответ, но ещё не рабочий бюджет. Завершённая задача API — не обязательно готовый клип. Если ревью отклонит половину попыток, бюджет вырастет до $5.04 в месяц. Хранилище, планирование, редактирование и ревью находятся вне этого.
Это руководство рассчитывает честное число и строит пример с одним рабочим, который останавливается для ручного согласования вместо угадывания повтора неопределённого POST.
TL;DR
- Одна задача Seedance 2.0 Mini на 5 секунд, 480p, 9:16 потребила 84 кредита = $0.084. Тридцать таких попыток обошлись бы $2.52.
- Бюджетируйте по завершённым попыткам на принятый клип, а не по запланированным постам. При 1.5 попыток на клип месячный бюджет $3.78; при двух — $5.04.
- Новые аккаунты могут получить рекламные кредиты, но публичная страница цен не обещает фиксированное количество или ежедневный сброс.[3] Рассматривайте их как протоип, а не ежемесячную вместимость.
- Сохраняйте ID задачи сразу. Каждый новый
POSTсоздаёт отдельную задачу и резервирование; каждая завершённая задача рассчитывает собственное использование.Idempotency-Key— это трассировочное значение, не дедублирование видеозапросов.[4] - Опрашивайте с
GETкаждые пять секунд, архивируйте результат в подконтрольное хранилище и публикуйте за ручным ревью.[5] - 107.2 секунды — это одиночный тест, а не утверждение про среднюю скорость, надёжность или качество.
Вопрос про ежедневное видео
Нужен ли реальный REST API, создающий один-два коротких вертикальных клипа в день, возвращающий публичный HTTPS URL и встраивающийся в поток публикации? Для прототипа 9:16 в 4–5 секунд стоимость — только половина. Восстановление важно когда прототип становится расписанием: нужно устойчивое состояние и политика повторов перед умным промптом.
Один забег на 107 секунд
Тест использовал самую дешёвую конфигурацию reAPI, принимающую текст и поддерживающую 9:16 с 4–5 секундами: Seedance 2.0 Mini на 480p.[1] Модель поддерживает 480p или 720p, 9:16 и 4–15 секунд.[2]
| Параметр | Значение |
|---|---|
| Дата | 3 сентября 2026 |
| ID задачи | task_01a06547163473ecb7dab4478ee1abaa |
| Модель | seedance-2.0-mini |
| Запрос | 480p, 9:16, 5 сек |
| Аудио | Выкл |
| Водяной знак | Выкл |
| Отправок | 1 |
| Статус | Завершено |
| Время | 107.2 сек |
| Использование | 84 кредита / $0.084 |
| Результат | 1 URL видео |
Этот результат: 5 сек, 480p, 9:16, аудио и водяной знак отключены. Проверены завершение и платёж; качество не оценивалось.
Ставка 480p составляет $0.016625 за секунду.[1] reAPI: 1 кредит = $0.001, округление вверх.[2] Расчёт:
ceil($0.016625 × 5 × 1,000)
= ceil(83.125)
= 84
= $0.084POST резервирует кредиты для задачи. Рассчёт когда задача терминальна: читайте status с usage.credits, не считайте фиксацию финалом. Seedance 2.0 Mini возвращает неудачу по политике.[2][5]
Этот результат подтверждает путь, статус, URL и плату. Не устанавливает типичное время, успех, принятие или качество.
Загрузить запись. Содержит параметры, ID, время, статус и кредиты. Временный URL пропущен; запись указывает на постоянный CDN.
Цены меняются. Проверьте страницу Seedance 2.0 Mini перед бюджетом.
30-дневный бюджет
Минимальный расчёт:
30 × 84 = 2 520 кредитов = $2.52Один клип в день. Полезная формула:
ежемесячная стоимость = дни × видео/день × попытки/видео × стоимость/попыткаЗа один клип в день:
| Попыток/видео | Всего попыток | Месячный бюджет |
|---|---|---|
| 1.0 | 30 | $2.52 |
| 1.5 | 45 | $3.78 |
| 2.0 | 60 | $5.04 |
| 3.0 | 90 | $7.56 |
"1.5" — среднее: 15 первых попыток, 15 замен. Считайте отклонённые за мотион, композицию, или расхождение.
Разрешение и время меняют цену. Цифры — текущие ставки; только 480p 5-сек был тестом:
| Конфигурация | Кредитов | Стоимость | 30 раз |
|---|---|---|---|
| 480p, 4 сек | 67 | $0.067 | $2.01 |
| 480p, 5 сек | 84 | $0.084 | $2.52 |
| 720p, 4 сек | 144 | $0.144 | $4.32 |
| 720p, 5 сек | 180 | $0.180 | $5.40 |
Это генерация. Исключает промпты, активы, редактирование, музыку, хранилище, хостинг, платежи и время ревью.
Свободные кредиты недостаточны
Свободные кредиты доказывают auth, поля, опрос, загрузку. Не гарантируют без суммы и сброса.
Новые аккаунты получают рекламные кредиты; показаны при регистрации. Публичная цена не обещает фиксацию или сброс.[3] Непригодны как месячная вместимость. То же на приложения: без API доступа, лимитов, сброса — UI кредиты не бюджет.
Тестируйте узкий путь. Бюджетируйте платное и рассматривайте свободные как временное. Это деле после запуска, не на демо.
Перед автоматизацией
Подготовьте:
- Аккаунт reAPI и серверный ключ. Не в браузер, репо или скачиваемый рабочий.
- Промпт на короткий кадр. 5 сек — не для истории.
- Планировщик: cron, GitHub Actions, n8n, очередь.
- Место для ежедневного ключа и ID задачи.
- Хранилище для готовых файлов.
- Человек для ревью перед публикацией.
Примеры — UTC. Если локальное время, считайте дату в том поясе. Около полуночи может быть неправильный ключ.
Отправить видео 9:16 cURL
Установите ключ:
export REAPI_API_KEY='replace-with-your-server-side-key'Отправьте и сохраните:
curl --fail-with-body --silent --show-error \
--request POST 'https://reapi.ai/api/v1/videos/generations' \
--header "Authorization: Bearer $REAPI_API_KEY" \
--header 'Content-Type: application/json' \
--data '{
"model": "seedance-2.0-mini",
"prompt": "A handmade ceramic cup beside an open notebook, soft morning window light, one slow push-in shot, natural motion, no text",
"resolution": "480p",
"aspect_ratio": "9:16",
"duration": 5,
"generate_audio": false,
"watermark": false
}' \
--output submit.jsonОткройте submit.json и скопируйте id. Если jq:
TASK_ID="$(jq -r '.id' submit.json)"
test -n "$TASK_ID" && test "$TASK_ID" != 'null' || exit 1
printf '%s\n' "$TASK_ID" > task-id.txtОпрос GET не тратит кредиты:[5]
curl --fail-with-body --silent --show-error \
--header "Authorization: Bearer $REAPI_API_KEY" \
"https://reapi.ai/api/v1/tasks/$TASK_ID" \
--output task.json
jq '{id, status, usage, output, error}' task.jsonПовторяйте через 5 сек пока processing. Финалы: completed или failed. Не повторяйте POST если видео ещё нет.
Безопасный рабочий в Node.js
cURL доказывает поля. Скрипт ниже — один рабочий, не-более-один раз, не очередь. Сохраняет намерение перед POST, записывает ID как прибыл ответ, ограничивает вызовы, архивирует, останавливается на неопределённость. Node.js 20+, без пакетов. Не две копии на файл.
Сохраните daily-video.mjs:
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
import { join } from 'node:path';
const API_BASE = 'https://reapi.ai/api/v1';
const STORE_PATH = './daily-video-jobs.json';
const OUTPUT_DIR = './daily-video-output';
const POLL_MS = 5_000;
const POLL_LIMIT_MS = 30 * 60 * 1_000;
const POST_TIMEOUT_MS = 30_000;
const GET_TIMEOUT_MS = 20_000;
const DOWNLOAD_TIMEOUT_MS = 120_000;
const apiKey = process.env.REAPI_API_KEY;
if (!apiKey) {
throw new Error('Set REAPI_API_KEY in the server environment.');
}
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
function retryAfterMs(value) {
if (!value) return POLL_MS;
const seconds = Number(value);
if (Number.isFinite(seconds)) return Math.max(seconds * 1_000, 0);
const date = Date.parse(value);
return Number.isNaN(date) ? POLL_MS : Math.max(date - Date.now(), 0);
}
async function loadJobs() {
try {
return JSON.parse(await readFile(STORE_PATH, 'utf8'));
} catch (error) {
if (error.code === 'ENOENT') return {};
throw error;
}
}
async function saveJobs(jobs) {
const temporaryPath = `${STORE_PATH}.tmp`;
await writeFile(temporaryPath, `${JSON.stringify(jobs, null, 2)}\n`);
await rename(temporaryPath, STORE_PATH);
}
async function requestJson(url, options) {
const response = await fetch(url, options);
const body = await response.text();
let data;
try {
data = JSON.parse(body);
} catch {
data = { raw: body };
}
if (!response.ok) {
const error = new Error(`HTTP ${response.status}: ${body.slice(0, 300)}`);
error.status = response.status;
error.retryAfterMs = retryAfterMs(response.headers.get('retry-after'));
error.requestId = data?.error?.request_id ?? null;
throw error;
}
return data;
}
async function archiveVideo(url, jobKey) {
const response = await fetch(url, {
signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS),
});
if (!response.ok) {
throw new Error(`Video download failed with HTTP ${response.status}.`);
}
await mkdir(OUTPUT_DIR, { recursive: true });
const safeName = jobKey.replace(/[^a-z0-9-]/gi, '_');
const outputPath = join(OUTPUT_DIR, `${safeName}.mp4`);
const bytes = Buffer.from(await response.arrayBuffer());
await writeFile(outputPath, bytes);
return outputPath;
}
async function main() {
const utcDate = new Date().toISOString().slice(0, 10);
const jobKey = `daily-short:${utcDate}`;
const jobs = await loadJobs();
if (!jobs[jobKey]) {
// Persist intent before POST. A crash after this point must not cause an
// automatic second submission on the next scheduler run.
// Save completion before downloading so storage trouble cannot trigger POST.
jobs[jobKey] = {
state: 'submitting',
createdAt: new Date().toISOString(),
idempotencyKey: jobKey,
};
await saveJobs(jobs);
try {
const task = await requestJson(`${API_BASE}/videos/generations`, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
// Trace-only on reAPI. This header does not deduplicate the POST.
'Idempotency-Key': jobKey,
},
signal: AbortSignal.timeout(POST_TIMEOUT_MS),
body: JSON.stringify({
model: 'seedance-2.0-mini',
prompt:
'A handmade ceramic cup beside an open notebook, soft morning ' +
'window light, one slow push-in shot, natural motion, no text',
resolution: '480p',
aspect_ratio: '9:16',
duration: 5,
generate_audio: false,
watermark: false,
}),
});
if (!task.id) throw new Error('Submission returned no task ID.');
jobs[jobKey] = {
...jobs[jobKey],
state: 'processing',
taskId: task.id,
submittedAt: new Date().toISOString(),
};
await saveJobs(jobs);
} catch (error) {
const receivedHttpResponse = Number.isInteger(error.status);
jobs[jobKey] = {
...jobs[jobKey],
state: receivedHttpResponse ? 'submit_rejected' : 'submit_uncertain',
error: error instanceof Error ? error.message : String(error),
requestId: error.requestId ?? null,
};
await saveJobs(jobs);
throw new Error(
receivedHttpResponse
? `Submission for ${jobKey} was rejected. Review the HTTP error ` +
'before creating a separately counted retry.'
: `Submission for ${jobKey} is uncertain. Use ${jobKey} and the ` +
'saved request ID, if present, to inspect logs or the dashboard. ' +
'Do not submit again until a person reconciles the result.',
);
}
}
let job = jobs[jobKey];
if (job.state === 'pending_review' || job.state === 'approved') {
console.log(`${jobKey} already has an archived output: ${job.archivePath}`);
return;
}
if (job.state === 'completed_no_output') {
throw new Error(
`${jobKey} completed without a video URL. Inspect ${job.taskId}; do not POST again.`,
);
}
if (job.state === 'failed') {
throw new Error(
`${jobKey} failed. Review its settled usage before creating a new retry key.`,
);
}
if (!job.taskId) {
throw new Error(
`${jobKey} has no task ID. Resolve ${job.state} manually; do not resubmit.`,
);
}
if (!job.outputUrl) {
const deadline = Date.now() + POLL_LIMIT_MS;
let task;
while (Date.now() < deadline) {
try {
task = await requestJson(`${API_BASE}/tasks/${job.taskId}`, {
headers: { Authorization: `Bearer ${apiKey}` },
signal: AbortSignal.timeout(GET_TIMEOUT_MS),
});
} catch (error) {
const remainingMs = Math.max(deadline - Date.now(), 0);
if (error.status === 429) {
const waitMs = Math.min(error.retryAfterMs ?? POLL_MS, remainingMs);
console.warn(`Rate limited; waiting ${waitMs} ms before another GET.`);
if (waitMs > 0) await sleep(waitMs);
continue;
}
const networkError = !Number.isInteger(error.status);
const serverError = error.status >= 500 && error.status < 600;
if (!networkError && !serverError) {
throw error;
}
const waitMs = Math.min(POLL_MS, remainingMs);
console.warn('Network or server error; retrying the same task GET.');
if (waitMs > 0) await sleep(waitMs);
continue;
}
if (task.status === 'completed' || task.status === 'failed') break;
if (task.status !== 'processing') {
throw new Error(`Unexpected task status: ${task.status}`);
}
await sleep(Math.min(POLL_MS, Math.max(deadline - Date.now(), 0)));
}
if (!task || (task.status !== 'completed' && task.status !== 'failed')) {
jobs[jobKey] = { ...job, state: 'poll_timeout' };
await saveJobs(jobs);
throw new Error(
'Polling timed out. The task may still be running; do not POST again.',
);
}
if (task.status === 'failed') {
jobs[jobKey] = {
...job,
state: 'failed',
usageCredits: task.usage?.credits ?? null,
taskError: task.error ?? null,
};
await saveJobs(jobs);
throw new Error(
'Generation failed. Review settled usage before scheduling a retry.',
);
}
const outputUrl = task.output?.video_urls?.[0];
if (!outputUrl) {
jobs[jobKey] = {
...job,
state: 'completed_no_output',
usageCredits: task.usage?.credits ?? null,
completedAt: new Date().toISOString(),
};
await saveJobs(jobs);
throw new Error('Completed task returned no video URL; do not POST again.');
}
jobs[jobKey] = {
...job,
state: 'completed',
outputUrl,
usageCredits: task.usage?.credits ?? null,
completedAt: new Date().toISOString(),
};
await saveJobs(jobs);
job = jobs[jobKey];
}
try {
const archivePath = await archiveVideo(job.outputUrl, jobKey);
jobs[jobKey] = {
...job,
state: 'pending_review',
archivePath,
archiveError: null,
};
await saveJobs(jobs);
console.log(`Saved ${archivePath}. Review it before publishing.`);
} catch (error) {
jobs[jobKey] = {
...job,
state: 'archive_failed',
archiveError: error instanceof Error ? error.message : String(error),
};
await saveJobs(jobs);
throw new Error(
'Archiving failed. The task remains completed; rerun to retry only the download.',
);
}
}
await main();Запустите:
node daily-video.mjsJSON перезапускаем на одной машине, но не мульти-рабочая блокировка. В прода вставьте строку БД с уникальным job_key, пусть только выигравший рабочий переместит с scheduled на submitting. БД блокировка предотвращает две одновременные отправки. Не может сделать запись и внешний API вызов атомарными.
После краша
Безопасное действие зависит от последнего сохранённого состояния:
| Состояние | Что знает | Действие |
|---|---|---|
| Нет строки | Намерение не сохранилось, POST не был | Начните нормально |
submitting/submit_uncertain, нет ID | POST может не начаться или принялся | Согласуйте вручную; не авто POST |
submit_rejected | Пришёл не-2xx | Проверьте ошибку, новая повторная попытка |
processing/poll_timeout, есть ID | Задача существует | Возобновите GET опрос |
failed | Терминал ошибка, расчёт | Проверьте usage.credits; новый ключ после решения |
completed/archive_failed, есть URL | Генерация готова | Повторите только загрузку |
completed_no_output | Закончилась без URL | Осмотрите; не POST |
pending_review/approved | Архивирован | Выход |
Неопределённость — неизбежный разрыв. Соединение может упасть после принятия POST. Скрипт отправляет ключ как Idempotency-Key для логов, но reAPI только записывает для трассировки.[4] Второй POST создаст другую задачу. Нет честного автоматического точно-один раза.
GET другой. Повтор не создаёт генерацию и не тратит кредиты. Пример ограничивает запросы, стопит 4xx, чтит Retry-After на 429, повторяет сеть/5xx в 30-минутном окне. 5-сек интервал избегает кэша в полёте.[5]
Проверьте перед публикацией
Задача API заканчивается доставкой. Готовый клип может не подходить или упасть на ленте. Проверьте:
- Предмет, действие, движение камеры;
- Искажённые объекты, руки, лица, упаковка, логотипы;
- Нежелаемые слова, выдуманные утверждения;
- Мерцание, смены сцен, опасные кадры;
- Права на промпт, материалы, музыку, лица;
- Требования платформы.
Отметьте approved только после. Если нет, создайте daily-short:2026-09-03:retry-1; не стирайте первую из реестра.
Переместите MP4 перед добавлением в очередь. URL reAPI — место передачи, не библиотека.[5] Сохраняйте локально; используйте S3, R2 или своё на эфемерном хосте.
Что не обещает $2.52
Месячное число — прозрачный сценарий, не гарантия. Предполагает ту же цену, время, разрешение и попыток 30 дней. Не устанавливает:
- Типичное время из одного теста 107.2 сек;
- Надёжность или отказ;
- Принятие визуально;
- Точные размеры сверх 480p и 9:16;
- Успешность публикации;
- Будущие цены или кредиты.
Держите переменные видимыми. Записывайте job_key, task_id, параметры, статус, usage.credits, ревью, URL. Через 30 дней замените число на ваше.
FAQ
Сколько 5-сек видео в день?
Seedance 2.0 Mini: 84 кредита, $0.084 за одну задачу. В день 30 дней $2.52. Проверьте цену перед бюджетом.
Два видео в день?
60 попыток $5.04. Умножьте на ваши попытки/видео. 1.5 = $7.56.
Бесплатный API с суточным сбросом?
Не предполагайте без документированного доступа, суммы, моделей, сброса. reAPI выдаёт рекламные кредиты при регистрации; публичная цена не обещает.[3]
Почему считать попытки, не клипы?
API может готовый клип, но ревью отклонит. Счёт по генерации; календарь по принятым. Оба числа раскрывают реальную стоимость.
Стоят ли неудачи?
Документация: неудачи возвращаются автоматически.[2] Всё равно записывайте финальный статус и usage.credits. Неудача стоит времени и замены.
Безопасно повторить с тем же ключом?
Нет. Каждый POST — отдельная задача и резервирование; каждая рассчитывает свои usage.credits. Idempotency-Key — трассировочное, не дедублирование.[4] Сохраняйте свой ключ и ID, стопите на неопределённость.
Публиковать прямо из URL?
Сначала архивируйте. URL — место передачи, не хранилище. Прямо пропускает ревью. Сохраните, проверьте, передайте своё.[5]
Нормально ли 107.2 сек?
Не знаем. Один тест. Типичное требует много дат, выборки, включая отказы и таймауты.
Заключение
Ответ на "Сколько стоит?" не просто $0.084. $2.52 идеально или $3.78–$7.56 при 1.5–3 попыток/клип. Начните с диапазона, измеряйте свой процент и держите свободные вне плана.
Первый рубеж: один ключ, один ID, безопасный GET, один архив, одобрение. Работает — планирование каждый день легко.
Ссылки
- reAPI. Каталог видео и Seedance 2.0 Mini. 3 сентября 2026.
- reAPI. Документация Seedance 2.0 Mini. 3 сентября 2026.
- reAPI. Цена. 3 сентября 2026.
- reAPI. API. 3 сентября 2026.
- reAPI. Задачи API. 3 сентября 2026.
- reAPI. Запись теста Seedance 2.0 Mini. Задача
task_01a06547163473ecb7dab4478ee1abaa, 3 сентября 2026. Один 480p, 9:16, 5-сек запрос без аудио и водяного знака; 84 кредита, 107.2 сек, один URL.
Дальнейшее чтение
Автор

Категории
Ещё статьи

Как отключить запросы разрешений в Claude Code
Шесть режимов разрешений Claude Code: автоматический режим с классификатором, правила для повторяющихся команд, альтернатива ручному подтверждению.


Seedream 5.0 Lite vs Pro: цена, редактирование и качество
Сравнение Seedream 5.0 Lite и Pro: различия в цене, разрешении, редактировании, ссылках на изображения, пакетной выдаче и использовании через API.


Как управлять движением видео AI через раскадровку
Практическое руководство по преобразованию сложного движения в упорядоченные ключевые кадры с определением ролей, промптами, тестами и проверкой результатов.
