How to Generate AI Video with Seedance 2.5 and 2.0 via the Dreamina API
6 min read • June 19, 2026 (October 23, 2026)
Table of contents
- Introduction
- Supported models
- Pricing
- Generate a video in two API calls
- Image-to-video (first / last frame)
- Batch-generate with a script
- Examples
- Frequently asked questions
- Conclusion
Introduction
Dreamina puts several frontier video models behind one account — Seedance 2.5 and 2.0 among them — and you can drive every one of them from code. Dreamina is the AI studio at dreamina.capcut.com from ByteDance, the company behind CapCut, and useapi.net fronts it with a third-party Dreamina API that runs on your Dreamina website subscription over REST.
Supported models
Dreamina runs both video and image models — pick one per request with the model field. Availability depends on your account region.
Video generation, on POST /videos (default seedance-2.0):
| Model | Region | Durations | Resolution | Input modes |
|---|---|---|---|---|
seedance-2.5 | US, CA | 4–30s, or 31–180s in long video mode | 480p, 720p, 1080p | Text, first/last frame, Omni Reference, long video, edit |
seedance-2.0 | US, CA | 4–15s | 720p, 1080p, 4k | Text, first/last frame, Omni Reference |
seedance-2.0-fast | US, CA | 4–15s | 720p, 1080p, 2k, 4k (above 720p, upscaled) | Text, first/last frame, Omni Reference |
seedance-2.0-mini | US, CA | 4–15s | 720p, 1080p, 2k, 4k (above 720p, upscaled) | Text, first/last frame, Omni Reference |
seedance-1.5-pro | US, CA | 5, 10, 12s | 720p, 1080p (CA) | Text, first/last frame |
seedance-1.0-pro | CA | 5, 10s | 1080p | Text, first frame |
seedance-1.0-mini | US | 5, 10s | 720p | Text, first frame, multi-frame |
seedance-1.0-fast | CA | 5, 10s | 720p, 1080p | Text, first frame, multi-frame |
On seedance-1.5-pro 1080p is CA-only.
This guide focuses on video, but the same account and token also drive Dreamina’s image models — listed here for reference, on POST /images (default seedream-4.6, up to 4 images per request):
| Model | Region | Resolution | Max refs | Notes |
|---|---|---|---|---|
seedream-4.6 | US, CA | 2k–4k | 6 | Default · runs on a free account’s daily credits |
seedream-5.0-lite | US, CA | 2k–4k | 6 | — |
seedream-4.5 | US, CA | 2k–4k | 6 | — |
seedream-4.1 | US, CA | 2k–4k | 6 | — |
seedream-4.0 | US, CA | 2k–4k | 6 | |
seedream-3.0 | US, CA | 1k–2k | 1 | Prompt required |
nano-banana | CA | 1k | 3 | Prompt required |
gpt-image-2 | CA | 1k | 6 | Reference-only · OpenAI-sourced |
seedream-5.0-pro | CA | 1.5k–4k | 6 | Cinematic and text-rich visuals |
A free Dreamina account makes seedream-4.6 (the default) images on Dreamina’s free daily credits. For the full image workflow, see the images endpoint and the Dreamina API overview.
Pricing
What one 5-second Seedance 2.0 video costs on ByteDance’s official API, BytePlus ModelArk, and on a Dreamina Advanced website subscription billed yearly in each region (October 2026). Each subscription comes with a monthly number of credits, and each video uses a set number of them, so a video costs its share of the subscription.
| Model | Official API | US Advanced $75/m 8,645 cr/mo | Canada Advanced C$108.33/m 11,997 cr/mo |
|---|---|---|---|
| Seedance 2.0 Fast, 720p | $0.60 $0.12 a second | $0.35 / 40 cr 216 videos/mo | $0.32 / 50 cr 239 videos/mo |
| Seedance 2.0, 720p | $0.76 $0.152 a second | $0.74 / 85 cr 101 videos/mo | $0.74 / 115 cr 104 videos/mo |
| Seedance 2.0, 1080p | $1.87 $0.374 a second | $1.78 / 205 cr 42 videos/mo | $1.83 / 285 cr 42 videos/mo |
- Both regions run Seedance 2.0 at 1080p and 4K.
- Billed yearly, Advanced is $900 a year in the US and C$1,299.99 in Canada. Credit rates come from each region’s price metadata, read October 21, 2026, and Canada prices are converted to US dollars at CAD/USD 0.7112.
- The Dreamina overview cost calculator prices every model, including
seedance-2.5.
Generate a video in two API calls
You need a useapi.net API token and a connected Dreamina account — export the token so the curl examples below run as-is: export USEAPI_TOKEN="user:1234-...". Generation is asynchronous: the create call returns a jobid immediately, then you poll until the video is ready.
First, submit the job with POST https://api.useapi.net/v1/dreamina/videos:
curl -X POST "https://api.useapi.net/v1/dreamina/videos" \
-H "Authorization: Bearer $USEAPI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A serene mountain landscape at sunset, camera slowly panning right",
"model": "seedance-2.0",
"ratio": "16:9",
"duration": 5
}'
The response returns immediately with a jobid and status: "created":
{
"jobid": "j0223140530...CA:[email protected]:dreamina",
"type": "video",
"status": "created",
"model": "seedance-2.0",
"code": 200
}
Then poll for the result with GET https://api.useapi.net/v1/dreamina/videos/{jobid}:
curl "https://api.useapi.net/v1/dreamina/videos/JOBID" \
-H "Authorization: Bearer $USEAPI_TOKEN"
When status is completed, the finished MP4 is in response.videoUrl (the clean, non-watermarked master when available, with response.videoUrlWatermarked kept as a fallback):
{
"jobid": "j0223140530...",
"status": "completed",
"response": {
"videoUrl": "https://v16m-default.tiktokcdn.com/...",
"videoUrlWatermarked": "https://v16-cc.capcut.com/..."
},
"code": 200
}
Seedance 2.0 typically finishes in 60–180 seconds depending on model and duration. Result URLs are signed and expire about 7 days after generation, so download promptly. Prefer not to poll? Pass a replyUrl in the create body to receive a webhook callback when the job completes. A job can come back status: "failed", and the create call may return 402 (subscription expired or out of credits), 429 (too many requests), or 596 (account session error) — see the endpoint docs for the full list.
Image-to-video (first / last frame)
To animate a still image, upload it first with POST /assets/account (raw bytes, an image Content-Type, max 10 MB) — it returns an assetRef — then pass that ref as firstFrameRef (and optionally endFrameRef for a first→last transition):
# 1. Upload the start frame → returns { "assetRef": "..." }
curl -X POST "https://api.useapi.net/v1/dreamina/assets/US:[email protected]" \
-H "Authorization: Bearer $USEAPI_TOKEN" \
-H "Content-Type: image/jpeg" \
--data-binary @first_frame.jpeg
# 2. Create the video from that frame
curl -X POST "https://api.useapi.net/v1/dreamina/videos" \
-H "Authorization: Bearer $USEAPI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"prompt": "the character turns and smiles",
"model": "seedance-2.0",
"duration": 5,
"firstFrameRef": "ASSET_REF_FROM_STEP_1"
}'
When you provide image frames, the aspect ratio is auto-detected from the image — do not set ratio. A first+last frame pair must share the same aspect ratio.
Seedance 2.0 / 2.0 Fast reject real human faces at content moderation — use illustrated, anime, or stylized characters. For a working real-face workflow, see the Seedance 2.0 real-face tutorial (Runway → Dreamina), which generates the real-face start frame in Runway and animates it in Dreamina.
Batch-generate with a script
Finding the right shot takes many attempts, and running them by hand is tedious. The Node.js script below reads a list of prompts from prompts.json, uploads any first/last frame images, submits each job, then polls and downloads every finished MP4 — so you can queue a batch and come back to the winners.
You need Node.js v21 or newer. Put prompts.json and dreamina.mjs in the same folder and run node ./dreamina.mjs API_TOKEN EMAIL, where API_TOKEN is your useapi.net API token and EMAIL is your connected Dreamina account email. Dreamina accounts are identified as REGION:email (e.g. US:[email protected]), and the script looks yours up by email automatically.
Expand prompts.json
[
{
"prompt": "By default the seedance-2.0 model with a 16:9 ratio, 720p resolution and a 5-second duration will be used."
},
{
"model": "seedance-2.0",
"ratio": "16:9",
"duration": 10,
"resolution": "720p",
"prompt": "A serene mountain landscape at sunset with the camera slowly panning right. For all parameters see https://useapi.net/docs/api-dreamina-v1/post-dreamina-videos"
},
{
"model": "seedance-2.0",
"duration": 5,
"firstFrame": "./first_frame.jpeg",
"lastFrame": "./last_frame.jpeg",
"prompt": "Image-to-video with a start frame (firstFrame → firstFrameRef) and an end frame (lastFrame → endFrameRef). When image frames are provided, ratio is auto-detected and must not be set."
},
{
"model": "seedance-2.0-fast",
"duration": 5,
"firstFrame": "./image.jpeg",
"prompt": "Faster Seedance 2.0 Fast generation from a single start frame. Other models (seedance-2.5, seedance-2.0-mini, seedance-1.5-pro, on US accounts seedance-1.0-mini, and on CA accounts seedance-1.0-pro / seedance-1.0-fast) are selectable via the model field — see the videos docs."
}
]
Expand dreamina.mjs script
/*
Script version 1.0, June 19, 2026
Script to batch-generate videos using prompts with the Dreamina API v1 by useapi.net 🚀
Defaults to the seedance-2.0 model and uses the asynchronous videos endpoint.
For more details visit https://useapi.net/docs/api-dreamina-v1/post-dreamina-videos
Installation Instructions:
==========================
You need Node.js v21 or newer installed to run this script. Download and install Node.js from:
- Windows, macOS, Linux: https://nodejs.org/
After installation, verify by running the following command in a terminal:
node -v
Running the Script:
===================
Usage: node dreamina.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]
Replace API_TOKEN with your actual useapi.net API token, see https://useapi.net/docs/start-here/setup-useapi
Replace EMAIL with configured Dreamina email account, see https://useapi.net/docs/start-here/setup-dreamina
If optional PROMPTS_FILE not provided prompts.json will be used.
Example:
--------
node dreamina.mjs user:1234-abcdefhijklmnopqrstuv [email protected]
This command executes the script using API token user:1234-abcdefhijklmnopqrstuv with [email protected] Dreamina account email.
Changelog:
==========
- June 19, 2026: Initial release.
*/
import readline from 'node:readline';
import fs from 'fs/promises';
import path from 'path';
import { writeFile } from 'node:fs/promises';
import { Readable } from 'node:stream';
// Constants
const RESULTS_FILE = 'dreamina_results.txt';
const ERRORS_FILE = 'dreamina_errors.txt';
const DEFAULT_PROMPTS_FILE = 'prompts.json';
const DEFAULT_MODEL = 'seedance-2.0';
const SLEEP_429 = 10 * 1000; // in milliseconds
const MAX_429_RETRIES = 6; // give up a prompt after this many consecutive 429s (all accounts busy)
const SLEEP_DOWNLOAD = 20 * 1000; // in milliseconds
const urlAccounts = 'https://api.useapi.net/v1/dreamina/accounts';
const urlVideos = 'https://api.useapi.net/v1/dreamina/videos';
const urlVideosJob = 'https://api.useapi.net/v1/dreamina/videos/';
const urlAssets = 'https://api.useapi.net/v1/dreamina/assets/';
// Supported image extensions mapped to their upload Content-Type.
// See https://useapi.net/docs/api-dreamina-v1/post-dreamina-assets-account
const imageContentTypes = {
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
png: 'image/png',
webp: 'image/webp'
};
const supportedFileExtensions = Object.keys(imageContentTypes);
// { filename: assetRef }
const uploadedFiles = {};
// Utility to sleep for given milliseconds
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Function to fetch configured Dreamina API accounts
async function fetchAccounts(apiToken) {
const response = await fetch(urlAccounts, {
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${apiToken}`
}
});
if (!response.ok) {
console.error(`⛔ Error fetching accounts (HTTP ${response.status}): ${response.statusText}`);
process.exit(1);
}
return response.json();
}
const elapsedTimeSec = (start) => (Date.now() - start) / 1000;
// Upload a first/last frame image and return its reusable assetRef.
// The asset is uploaded to the account that owns the generation (REGION:email).
async function uploadAsset(apiToken, account, filename) {
// Check if already uploaded
if (uploadedFiles.hasOwnProperty(filename))
return uploadedFiles[filename];
const startTime = Date.now();
console.log(`⬆️ Account ${account} uploading file…`, filename);
const body = new Blob([await fs.readFile(filename)]);
const fileExt = filename.split('.').pop().toLowerCase();
const contentType = imageContentTypes[fileExt];
const response = await fetch(`${urlAssets}${encodeURIComponent(account)}`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${apiToken}`,
'Content-Type': contentType
},
body
});
if (response.ok) {
const json = await response.json();
const { assetRef } = json;
console.log(`🆗 assetRef (${elapsedTimeSec(startTime)} sec)`, assetRef);
uploadedFiles[filename] = assetRef;
}
else {
console.error(`❗ Unable to upload file HTTP ${response.status} (${elapsedTimeSec(startTime)} sec)`, await response.text());
// Do not attempt to upload failed file again
uploadedFiles[filename] = undefined;
}
return uploadedFiles[filename];
}
async function submit(apiToken, url, body, index, prompt) {
const createResponse = await fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiToken}`
},
body
});
const createBody = await createResponse.text();
if (createResponse.status == 200) {
const json = JSON.parse(createBody);
const { jobid } = json;
if (jobid) {
await fs.appendFile(RESULTS_FILE, `${jobid},#${index}:${prompt}\n`);
console.log(`✅ jobid`, jobid);
return 200;
} else {
const error = `No jobid found in HTTP 200 response`;
console.log(`❓ ${error}`, createBody);
await fs.appendFile(ERRORS_FILE, `${error},#${index}:${prompt}\n`);
return 500;
}
} else {
switch (createResponse.status) {
case 429:
console.log(`🔄️ Retry on HTTP ${createResponse.status} (all accounts at capacity)`);
break;
case 400:
console.log(`🛑 Validation error`, createBody);
await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${prompt}\n`);
break;
case 402:
console.log(`🛑 Subscription expired or insufficient credits`, createBody);
await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${prompt}\n`);
break;
case 596:
console.log(`🛑 Account session expired — re-add the account at https://useapi.net/docs/api-dreamina-v1/post-dreamina-accounts`, createBody);
await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${prompt}\n`);
break;
default:
console.log(`❗ FAILED with HTTP ${createResponse.status}`, createBody);
await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${prompt}\n`);
}
return createResponse.status;
}
}
// Submit a single prompt to the videos endpoint.
// firstFrame → firstFrameRef (start frame), lastFrame → endFrameRef (end frame).
async function submitVideo(apiToken, account, prompt, index) {
const { model, prompt: text, firstFrame, lastFrame, ratio, duration, resolution } = prompt;
const useModel = model ?? DEFAULT_MODEL;
console.log(`🚀 ${useModel} » Prompt #${index} • account ${account} • ${duration ?? 5} secs …`);
const firstFrameRef = firstFrame ? await uploadAsset(apiToken, account, firstFrame) : undefined;
const endFrameRef = lastFrame ? await uploadAsset(apiToken, account, lastFrame) : undefined;
// ratio is auto-detected from image dimensions and must not be sent when frames are provided.
const useRatio = (firstFrameRef || endFrameRef) ? undefined : ratio;
const body = JSON.stringify({
account,
model: useModel,
prompt: text,
ratio: useRatio,
duration,
resolution,
firstFrameRef,
endFrameRef
});
return await submit(apiToken, urlVideos, body, index, text);
}
// Function to download videos
async function download(apiToken) {
if (! await fileExists(RESULTS_FILE)) return;
try {
const resultsContent = await fs.readFile(RESULTS_FILE, 'utf8');
const lines = resultsContent.trim().split('\n');
for (const line of lines) {
const [jobid, prompt] = line.split(',');
const videoFilename = `${jobid.replace(/:/g, '_')}.mp4`;
console.log(`👉 ${jobid}`);
try {
await fs.access(videoFilename);
console.log(`⚠️ ${videoFilename} already exists. Skipping download.`);
continue;
} catch {
// File does not exist, proceed with downloading
}
while (true) {
const response = await fetch(`${urlVideosJob}${jobid}`, {
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${apiToken}`
}
});
if (!response.ok) {
console.log(`🛑 Poll failed ${jobid} (HTTP ${response.status}):\n${prompt}\n`, await response.text());
break;
}
const job = await response.json();
const { status, response: result, error, errorDetails } = job;
if (status == 'failed') {
console.error(`🛑 FAILED ${jobid} (${error}${errorDetails ? ` — ${errorDetails}` : ''}):\n${prompt}\n`);
break;
}
if (status == 'completed') {
// Prefer the clean master; fall back to the watermarked variant.
const url = result?.videoUrl ?? result?.videoUrlWatermarked;
if (url) {
console.log(`✅ Downloading ${url} to ${videoFilename}`);
try {
const videoResponse = await fetch(url);
if (!videoResponse.ok) {
console.error(`⛔ Unable to download ${jobid} (HTTP ${videoResponse.status}):\n${prompt}\n`, url);
break;
}
const stream = Readable.fromWeb(videoResponse.body);
await writeFile(videoFilename, stream);
} catch (err) {
console.error(`⛔ Error during download: ${err}`);
}
} else
console.error(`🛑 Unable to download ${jobid}, no videoUrl in completed job:\n${prompt}\n`);
break;
}
console.log(`⌛ ${jobid} status (${status}) and is still in progress, waiting…`);
await sleep(SLEEP_DOWNLOAD);
}
}
} catch (error) {
console.log(`⛔ Error during download:`, error.stack || error);
}
}
// Main function
async function main() {
const apiToken = process.argv[2];
const email = process.argv[3];
const promptFile = process.argv[4] || DEFAULT_PROMPTS_FILE;
if (!apiToken || !email) {
console.error('Usage: node dreamina.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]');
process.exit(1);
}
console.info('Script v1.0');
console.info('Node version is: ' + process.version);
try {
if (await fileExists(RESULTS_FILE)) {
let user_input;
while (!['y', 'n'].includes(user_input)) {
user_input = (await promptUser(`❔ ${RESULTS_FILE} file detected. Do you want to download the results now? (y/n): `))?.toLowerCase();
if (user_input == 'y') {
await download(apiToken);
await fs.unlink(RESULTS_FILE);
}
}
}
const start = new Date();
try {
console.info('START EXECUTION', start);
await execute(apiToken, email, promptFile); // Pass the promptFile to execute function
}
finally {
console.info('COMPLETED', new Date());
console.info('EXECUTION ELAPSED', diffInMinutesAndSeconds(start, new Date()));
}
try {
console.info('START DOWNLOAD', start);
await download(apiToken);
}
finally {
console.info('TOTAL ELAPSED', diffInMinutesAndSeconds(start, new Date()));
}
} catch (error) {
console.error('⛔ Error during execution:', error.stack || error);
}
}
// Modify the execute function to accept promptFile as a parameter
async function execute(apiToken, email, promptFile) {
const accounts = await fetchAccounts(apiToken);
const accountList = Object.values(accounts);
console.info(`Configured Dreamina API accounts (${accountList.length}):`, accountList.map(a => a.account).join(', '));
if (accountList.length <= 0) {
console.error(`⛔ No configured Dreamina accounts found. Please refer to https://useapi.net/docs/start-here/setup-dreamina`);
process.exit(1);
}
// Dreamina accounts are keyed as REGION:email — match by email.
const matched = accountList.find(a => a.email === email);
if (!matched) {
console.error(`⛔ Account with email ${email} not found. Please refer to https://useapi.net/docs/start-here/setup-dreamina`);
process.exit(1);
}
if (matched.error) {
console.error(`⛔ Account ${matched.account} has pending error. Please resolve and re-add the account at https://useapi.net/docs/api-dreamina-v1/post-dreamina-accounts`);
process.exit(1);
}
const account = matched.account;
const promptData = await fs.readFile(promptFile, 'utf8');
const prompts = JSON.parse(promptData);
console.log(`Total number of prompts to process`, prompts.length);
let warnings = [];
// Parameters accepted by this script for the videos endpoint.
// See https://useapi.net/docs/api-dreamina-v1/post-dreamina-videos for the full parameter set.
const supportedParams = ['model', 'prompt', 'firstFrame', 'lastFrame', 'ratio', 'duration', 'resolution'];
const invalidKeys = (prompt) => Object.keys(prompt).filter(key => !key.startsWith('__') && !supportedParams.includes(key))
for (let i = 1; i <= prompts.length; i++) {
const prompt = prompts[i - 1];
const { prompt: text, firstFrame, lastFrame } = prompt;
const validateImage = async (file) => {
if (file) {
try {
await fs.access(file);
} catch {
warnings.push(`⚠️ Image '${file}' does not exist. Prompt ${i}`);
}
const ext = file.split('.').pop().toLowerCase();
if (!supportedFileExtensions.includes(ext))
warnings.push(`⚠️ Image ${file} extension ${ext} not supported. Prompt ${i}`);
}
};
const notSupported = invalidKeys(prompt);
if (notSupported.length)
warnings.push(`⚠️ Following params not supported: ${notSupported.join(',')}. Prompt ${i}`);
if (!text && !firstFrame)
warnings.push(`⚠️ Please specify a prompt and/or a firstFrame image. Prompt ${i}`);
if (lastFrame && !firstFrame)
warnings.push(`⚠️ lastFrame (endFrameRef) requires firstFrame (firstFrameRef). Prompt ${i}`);
await Promise.all([validateImage(firstFrame), validateImage(lastFrame)]);
}
if (warnings.length > 0) {
warnings.forEach(warning => console.warn(warning));
console.error(`⛔ Execution stopped due to warnings.`);
process.exit(1);
}
for (let i = 0; i < prompts.length; i++) {
const prompt = prompts[i];
let retries429 = 0;
while (true) {
const responseCode = await submitVideo(apiToken, account, prompt, i + 1);
if (responseCode == 429) {
if (++retries429 > MAX_429_RETRIES) {
console.error(`⛔ Gave up on prompt #${i + 1} after ${MAX_429_RETRIES} retries — all accounts still busy.`);
await fs.appendFile(ERRORS_FILE, `429 (gave up after ${MAX_429_RETRIES} retries),#${i + 1}\n`);
break;
}
await sleep(SLEEP_429);
}
else
if (responseCode == 402 || responseCode == 596) {
process.exit(1);
} else
break;
}
}
}
// Utility function to check if a file exists
async function fileExists(path) {
try {
await fs.access(path);
return true;
} catch {
return false;
}
}
// Function to prompt user input
async function promptUser(query) {
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
return new Promise((resolve) => rl.question(query, answer => {
rl.close();
resolve(answer);
}));
}
function diffInMinutesAndSeconds(date1, date2) {
const diffInSeconds = Math.floor((date2 - date1) / 1000);
return `${Math.floor(diffInSeconds / 60)} minutes ${diffInSeconds % 60} seconds`;
};
main();
Examples
The clips below are real Seedance 2.0 generations produced through this Dreamina API, straight from our blog walkthroughs.
Omni Reference — interleaved text + image references (@image1/@image2/@image3)
— from Dreamina: Seedance 2.0 Video Generation
Text-to-video — prompt only, with natively generated audio
— from Dreamina: Seedance 2.0 Launch Examples
More Seedance 2.0 clips from that post on YouTube: Selfie Situation • Seedance 2.0, A Very Talented Man • Seedance 2.0.
Omni Reference with a real face — 15s 9:16 (Runway → Dreamina workflow)
— from Seedance 2.0: Using Real Faces
Related tutorials: Seedance 2.0 and 2.5 API pricing compared, Sora 2 API alternatives and PixVerse V6 video via the PixVerse API.
Frequently asked questions
Is there a Seedance 2.0 API? Through useapi.net, yes: the Dreamina API runs Seedance 2.0 and the rest of the Seedance family on your Dreamina website subscription over REST, and Dreamina has no public developer API of its own (as of October 2026). The same route runs long Seedance 2.5 videos of 31 to 180 seconds in one job, where ByteDance’s BytePlus ModelArk stops at 30 seconds a clip.
How much does Seedance 2.0 cost through the API? Through useapi.net, a 5-second Seedance 2.0 video at 1080p costs about $1.78 on a US Dreamina Advanced website subscription billed yearly ($1.83 in Canada), against $1.87 on ByteDance’s BytePlus ModelArk, and a 720p Seedance 2.0 Fast video about $0.32 against $0.60 (as of October 2026). See Pricing for both plans.
Do I need ByteDance enterprise approval? Through useapi.net, no. You call the API with a useapi.net API token and connect your Dreamina website subscription through Setup Dreamina, with no BytePlus account, no prepaid pack and no enterprise onboarding. On Seedance 2.5 it also accepts photographic portraits in references, which ByteDance’s official API restricts to verified assets or an enterprise contract from $14,000 a year (see the Seedance pricing comparison).
Can I generate images (Seedream, Nano Banana) too? Through useapi.net, yes. The same Dreamina website subscription drives POST /images with Seedream 5.0 Pro, 5.0 Lite, 4.6, 4.5, 4.1, 4.0 and 3.0, nano-banana and gpt-image-2, up to 4 images per request. The default seedream-4.6 also runs on a free account’s daily credits. See Supported models above.
Conclusion
Visit our Discord Server or
Telegram Channel for any support questions and concerns.
The full runnable example is in the dreamina-api GitHub repo.