How to Generate AI Video with Seedance 2.0 and Sora 2 via the Dreamina API
6 min read β’ July 19, 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.0 and Sora 2 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 your own Dreamina account 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.0 | US, CA | 4β15s | 720p, 1080p (CA) | Text, first/last frame, Omni Reference |
seedance-2.0-fast | US, CA | 4β15s | 720p | Text, first/last frame, Omni Reference |
seedance-1.5-pro | US, CA | 5, 10, 12s | 720p, 1080p | Text, first/last frame |
seedance-1.0-pro | CA | 5, 10s | 1080p | Text, first frame |
seedance-1.0-mini | US, CA | 5, 10s | 720p, 1080p | Text, first frame, multi-frame |
seedance-1.0-fast | CA | 5, 10s | 720p, 1080p | Text, first frame, multi-frame |
sora2 | CA | 4, 8, 12s | 720p | Text, first frame |
1080p is CA-only. seedance-2.0-fast and sora2 are 720p 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 Β· free |
seedream-5.0-lite | US, CA | 2kβ4k | 6 | Free |
seedream-4.5 | US, CA | 2kβ4k | 6 | β |
seedream-4.1 | US, CA | 2kβ4k | 6 | β |
seedream-4.0 | US, CA | 2kβ4k | 6 | Free |
seedream-3.0 | US, CA | 1kβ2k | 1 | Prompt required |
nano-banana | US, CA | 1k | 3 | Prompt required |
gpt-image-2 | CA | 1k | 3 | Reference-only Β· OpenAI-sourced |
The seedream-4.6 (default), seedream-5.0-lite, and seedream-4.0 image models are free to generate. For the full image workflow, see the images endpoint and the Dreamina API overview.
Pricing
You pay your normal Dreamina (CapCut) website subscription for the underlying account, plus a single flat $15/month to useapi.net that covers API access to every supported service β there are no per-model API surcharges. Approximate Seedance 2.0 / 2.0 Fast generation cost, per second of video:
| Model | US $/sec | CA $/sec |
|---|---|---|
| Seedance 2.0 Fast | $0.113 | $0.104 |
| Seedance 2.0 (720p) | $0.138 | $0.130 |
| Seedance 2.0 (1080p, CA only) | β | $0.313 |
So a 10-second 720p clip runs about $1.38 (US) or $1.30 (CA). See the Dreamina overview cost calculator for the full breakdown.
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.
1. Submit the job β 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
}
2. Poll for the result β 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; response.videoUrlWatermarked is 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.
Real human faces: 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]); 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 (720p only). Other models (seedance-1.5-pro, seedance-1.0-mini, and on CA accounts seedance-1.0-pro / seedance-1.0-fast / sora2) are selectable via the model field β see the videos docs."
}
]
Expand dreamina.mjs script
/*
Script version 1.0, July 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:
==========
- July 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 API: Seedance 2.0
Omni Reference with a real face β 15s 9:16 (Runway β Dreamina workflow)
β from Seedance 2.0: Using Real Faces
Frequently asked questions
Is there a Seedance 2.0 API? Yes β a few ways. ByteDance offers official Seedance APIs through BytePlus ModelArk / Volcengine, and third-party resellers expose Seedance too, all billed per generation at developer rates. useapi.net is the consumer-account route: programmatic access to Seedance 2.0 (and the rest of the Seedance family) by driving your own Dreamina (CapCut) account at the website subscription price through a standard REST endpoint.
Can I use Sora 2 through the Dreamina API? Yes. Pass "model": "sora2" to POST /videos on a CA-region Dreamina account. Sora 2 does text-to-video and first-frame image-to-video at 720p in 4, 8, or 12-second clips, billed under the same flat $15/month β no separate key or invite.
Do I need ByteDance enterprise approval? No. There is no enterprise onboarding or approval process β you connect your own Dreamina (CapCut) account, and your useapi.net API token authorizes every call.
How much does Seedance 2.0 cost through the API? You keep your normal Dreamina website subscription, plus a flat $15/month to useapi.net for API access to all services. Generation runs roughly $0.10β$0.14 per second of 720p video (about $1.30β$1.40 for a 10-second clip); 1080p on CA accounts is ~$0.31/sec. See Pricing above.
Can I turn an image into a video (image-to-video)? Yes. Upload the still with POST /assets/account and pass the returned assetRef as firstFrameRef (and optionally endFrameRef for a firstβlast transition). See Image-to-video above.
Can I generate images (Seedream, Nano Banana) too? Yes β the same account and flat $15/month also drive Dreaminaβs image models via POST /images: Seedream 5.0-lite / 4.6 / 4.5 / 4.1 / 4.0 / 3.0, nano-banana, and gpt-image-2. The seedream-4.6 (default), seedream-5.0-lite, and seedream-4.0 models are free to generate. See Supported models above.
How is this different from the official ByteDance API? Official Seedance APIs do exist β through BytePlus ModelArk / Volcengine and third-party resellers β but they bill per generation at developer/cloud rates. useapi.net instead automates your own consumer Dreamina (CapCut) account, so you generate at the website subscription price with no per-second metering, and the same one subscription covers 10+ other AI services.
My real-face video keeps getting rejected β why? Seedance 2.0 and 2.0 Fast block real human faces at content moderation. Use stylized characters, or follow the Runway β Dreamina real-face workflow that generates the start frame in Runway first.
Conclusion
Visit our Discord Server or
Telegram Channel for any support questions and concerns.
We regularly post guides and tutorials on the YouTube Channel.
The full runnable example is in the dreamina-api GitHub repo.