How to Generate Runway Gen Videos via API
6 min read • August 12, 2024 (June 22, 2026)
Table of contents
- Introduction
- Supported models
- Pricing
- Generate a video in two API calls
- Image-to-video (first / last frame)
- Beyond text-to-video
- Batch-generate with a script
- Examples
- Frequently asked questions
- Conclusion
Introduction
Runway hosts its own Gen-4.5 / Gen-4 / Gen-4 Aleph video and Frames images — and, behind the same account, the frontier models everyone else charges per call for — and you can drive every one of them from code. Runway is the generative-video studio behind the Gen series, and useapi.net fronts it with a third-party Runway API that runs your own Runway account over a standard REST endpoint — one unified videos/create call, no developer account, no per-generation metering from us.
The same account and token reach the third-party models Runway hosts — Veo 3.1, Sora 2, Kling, Seedance 2.0 and Wan for video, plus FLUX.2, Nano Banana and GPT Image for stills — so you can pick the right model per prompt without juggling a separate key for each vendor.
Supported models
The videos/create endpoint is unified — you pick a model per request with the model field, and the script defaults to gen4.5. The most-used video models are below. Capabilities differ by model.
Model (model) | Durations | Aspect ratios | Frames | Audio |
|---|---|---|---|---|
gen4.5 (default) | 2–10s | 16:9 (T2V) · all (I2V) | start frame | yes |
gen4 | 5s, 10s | all | start frame (required) | — |
gen4-turbo | 5s, 10s | all | start frame (required) | — |
veo-3.1 | 4s, 6s, 8s | 16:9, 9:16 | start + end | yes |
sora-2 | 4s, 8s, 12s | 16:9, 9:16 | start frame | always on |
kling-3.0-pro | 5s, 10s, 15s | 16:9, 9:16, 1:1 | start + end | yes |
kling-2.6-pro | 5s, 10s | 16:9, 9:16 | start frame | yes |
seedance-2 | 4–15s | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 | start + end | yes |
seedance-2-fast | 4–15s | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 | start + end | yes |
wan-2.6-flash | 5s, 10s, 15s | 16:9, 9:16, 1:1 | start frame (required) | yes |
That is the short list — videos/create also exposes kling-3.0-standard, kling-3.0-motion-control, the kling-o3-* omni tiers, kling-2.6-i2v, sora-2-pro, wan-2.2-animate, grok-imagine-1.5 and happyhorse-1.0. The endpoint page has the full per-model parameter tables. Among the frame-aware models, kling-3.0-pro and veo-3.1 accept an end frame for a first→last transition, while the Gen-4.x models take a single start frame only.
Pricing
This is the consumer-account route: you keep your normal Runway website subscription and add a flat $15/month to useapi.net that covers API access to every supported service, with no per-generation surcharge from us. Each generation draws from your Runway account’s own credit balance at Runway’s standard rates.
Generate a video in two API calls
You need a useapi.net API token and a connected Runway 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 task immediately, then you poll until the video is ready.
1. Submit the job — POST https://api.useapi.net/v1/runwayml/videos/create:
curl -X POST "https://api.useapi.net/v1/runwayml/videos/create" \
-H "Authorization: Bearer $USEAPI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gen4.5",
"text_prompt": "A cinematic aerial shot of a coastal city at golden hour, camera slowly pushing in",
"duration": 5,
"aspect_ratio": "16:9"
}'
The response returns immediately with a task object. The id you poll on is the taskId string:
{
"task": {
"taskId": "user:1234-runwayml:[email protected]:<uuid>",
"taskType": "gen4.5",
"status": "PENDING",
"artifacts": [],
"code": 200
}
}
2. Poll for the result — GET https://api.useapi.net/v1/runwayml/tasks/{taskId}:
curl "https://api.useapi.net/v1/runwayml/tasks/TASK_ID" \
-H "Authorization: Bearer $USEAPI_TOKEN"
The task is done when status is SUCCEEDED — the finished MP4 is the first entry of the artifacts array, at artifacts[0].url:
{
"status": "SUCCEEDED",
"artifacts": [
{ "url": "https://.../runway-result.mp4" }
]
}
A Gen-4.5 generation typically finishes in a couple of minutes — Gen-4 Turbo and Veo 3.1 are usually faster. Prefer not to poll? Pass a replyUrl in the create body to receive a webhook callback when the task completes or fails. The create call can return 412 (not enough credits — switch to a model or plan you have credits for), 422 (the prompt was moderated), or 429 (the account is busy — wait 10–30 seconds and retry). Up to two generations usually run in parallel per account, so add more Runway accounts to run a bigger batch at once.
Image-to-video (first / last frame)
To animate a still image, upload it first with POST /assets — the upload returns an assetId tied to the account it was uploaded to (that same account runs the generation). Pass it as imageAssetId1 for the start frame, and on the frame-aware models that support it (kling-3.0-pro, veo-3.1) add imageAssetId2 for the end frame:
# 1. Upload the start frame → returns { "assetId": "..." }
curl -X POST "https://api.useapi.net/v1/runwayml/assets/[email protected]&name=first.jpeg" \
-H "Authorization: Bearer $USEAPI_TOKEN" \
-H "Content-Type: image/jpeg" \
--data-binary @first.jpeg
# 2. Create the video from that frame
curl -X POST "https://api.useapi.net/v1/runwayml/videos/create" \
-H "Authorization: Bearer $USEAPI_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gen4.5",
"text_prompt": "the character turns and smiles",
"duration": 5,
"imageAssetId1": "ASSET_ID_FROM_STEP_1"
}'
Runway accepts .png, .jpeg and .gif images. You can also feed .webp — just rename the extension to .jpeg. A start → end frame pair (imageAssetId1 + imageAssetId2) is supported only by kling-3.0-pro and veo-3.1.
Beyond text-to-video
The same account and token also reach Runway’s other tools through their own endpoints, so the batch script extends naturally to more than videos/create:
- Frames images — Runway’s high-fidelity image model. POST /frames/create returns four 1080p images and lets you pass up to three reference images (
imageAssetId1–imageAssetId3, referenced as@IMG_1–@IMG_3in the prompt). A separate Runway Frames tutorial covers it end to end. - Act-Two — animate a character from a driving video plus an image or video reference, via POST /gen4/act-two.
- Images — a unified image endpoint for FLUX.2, Nano Banana / Pro, GPT Image and Seedream 5.
- 4K upscale — upscale any clip to 4K with Topaz.
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 (defaulting to gen4.5), then polls and downloads every finished MP4 — so you can queue a batch and come back to the winners.
You select the model per prompt with the model field, so a single prompts.json can mix Gen-4.5 text-to-video, a kling-3.0-pro first-and-last-frame shot, and a fast gen4-turbo image-to-video clip.
You need Node.js v21 or newer. Put prompts.json and runwayml.mjs in the same folder and run node ./runwayml.mjs API_TOKEN EMAIL, where API_TOKEN is your useapi.net API token and EMAIL is your connected Runway account email. It helps to feed your images to ChatGPT, Claude or Gemini along with Runway’s prompting guides and have it draft prompt variations for you — then keep the winners.
Expand prompts.json
[
{
"text_prompt": "By default the Gen-4.5 model with a 5-second duration will be used."
},
{
"model": "kling-3.0-pro",
"duration": 10,
"aspect_ratio": "16:9",
"firstImage": "./first_image.jpeg",
"lastImage": "./last_image.jpeg",
"text_prompt": "First-and-last-frame video with Kling 3.0 Pro: a start frame (firstImage → imageAssetId1) and an end frame (lastImage → imageAssetId2). Kling 3.0 Pro supports an end frame — the Gen-4.x models accept a single start frame only. For all parameters see https://useapi.net/docs/api-runwayml-v1/post-runwayml-videos-create"
},
{
"model": "gen4-turbo",
"duration": 5,
"firstImage": "./image.jpeg",
"text_prompt": "Faster Gen-4 Turbo generation from a single start frame. Other models (veo-3.1, kling-3.0-pro, sora-2, seedance-2, …) are selectable via the model field — see the videos/create docs."
}
]
Expand runwayml.mjs script
/*
Script version 3.1, June 22, 2026
Script to batch-generate videos using prompts with the Runway API v1 by useapi.net 🚀
Uses the unified videos/create endpoint (default model: Gen-4.5).
For more details visit https://useapi.net/docs/api-runwayml-v1/post-runwayml-videos-create
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 runwayml.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 Runway email account, see https://useapi.net/docs/start-here/setup-runwayml
If optional PROMPTS_FILE not provided prompts.json will be used.
Example:
--------
node runwayml.mjs user:1234-abcdefhijklmnopqrstuv [email protected]
This command executes the script using API token user:1234-abcdefhijklmnopqrstuv with [email protected] Runway account email.
Changelog:
==========
- June 22, 2026: Maintenance release.
- June 15, 2026: Migrated to the unified videos/create endpoint. Select the model via the prompt's model field (default gen4.5).
- October 22, 2024: Small bug fix with parameter validation.
*/
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 = 'runwayml_results.txt';
const ERRORS_FILE = 'runwayml_errors.txt';
const DEFAULT_PROMPTS_FILE = 'prompts.json';
const DEFAULT_MODEL = 'gen4.5';
const SLEEP_429 = 10 * 1000; // in milliseconds
const SLEEP_DOWNLOAD = 20 * 1000; // in milliseconds
const urlAccounts = 'https://api.useapi.net/v1/runwayml/accounts';
const urlVideosCreate = 'https://api.useapi.net/v1/runwayml/videos/create';
const urlDownload = 'https://api.useapi.net/v1/runwayml/tasks/';
const urlUploadAsset = 'https://api.useapi.net/v1/runwayml/assets/?email=';
// To upload .webp rename it to .jpeg
const supportedFileExtensions = ['png', 'jpeg', 'gif']
// { filename: assetId }
const uploadedFiles = {};
// Utility to sleep for given milliseconds
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
// Function to fetch configured Runway 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;
async function uploadAsset(apiToken, email, filename) {
// Check if already uploaded
if (uploadedFiles.hasOwnProperty(filename))
return uploadedFiles[filename];
const startTime = Date.now();
console.log(`⬆️ Account ${email} uploading file…`, filename);
const body = new Blob([await fs.readFile(filename)]);
const name = path.basename(filename);
const fileExt = filename.split('.').pop();
const response = await fetch(`${urlUploadAsset}${email}&name=${name}`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${apiToken}`,
'Content-Type': `image/${fileExt}`
},
body
});
if (response.ok) {
const json = await response.json();
const { assetId } = json;
console.log(`🆗 assetId (${elapsedTimeSec(startTime)} sec)`, assetId);
uploadedFiles[filename] = assetId;
}
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, text_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 { taskId } = json;
if (taskId) {
await fs.appendFile(RESULTS_FILE, `${taskId},#${index}:${text_prompt}\n`);
console.log(`✅ taskId`, taskId);
return 200;
} else {
const error = `No taskId found in HTTP 200 response`;
console.log(`❓ ${error}`, createBody);
await fs.appendFile(ERRORS_FILE, `${error},#${index}:${text_prompt}\n`);
return 500;
}
} else {
switch (createResponse.status) {
case 429:
console.log(`🔄️ Retry on HTTP ${createResponse.status}`);
break;
case 422:
console.log(`🛑 MODERATED prompt`, createBody);
await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${text_prompt}\n`);
break;
case 412:
console.log(`🛑 account run out of credits`, createBody);
break;
default:
console.log(`❗ FAILED with HTTP ${createResponse.status}`, createBody);
await fs.appendFile(ERRORS_FILE, `${createResponse.status},#${index}:${text_prompt}\n`);
}
return createResponse.status;
}
}
// Submit a single prompt to the unified videos/create endpoint.
// imageAssetId1 = start frame (firstImage or image), imageAssetId2 = end frame (lastImage).
async function submitVideo(apiToken, email, prompt, index) {
const { model, text_prompt, firstImage, lastImage, image, aspect_ratio, duration, seed } = prompt;
const useModel = model ?? DEFAULT_MODEL;
const exploreMode = prompt?.exploreMode;
const useDuration = duration ?? 5;
console.log(`🚀 ${useModel} » Prompt #${index} • account ${email} • ${useDuration} secs …`);
const startFrame = firstImage ?? image;
const imageAssetId1 = startFrame ? await uploadAsset(apiToken, email, startFrame) : undefined;
const imageAssetId2 = lastImage ? await uploadAsset(apiToken, email, lastImage) : undefined;
const body = JSON.stringify({
model: useModel,
email,
text_prompt,
aspect_ratio,
duration: useDuration,
seed,
exploreMode,
imageAssetId1,
imageAssetId2
});
return await submit(apiToken, urlVideosCreate, body, index, text_prompt);
}
// 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 [taskId, prompt] = line.split(',');
const videoFilename = `${taskId.replace(/:/g, '_')}.mp4`;
console.log(`👉 ${taskId}`);
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(`${urlDownload}${taskId}`, {
headers: {
'Accept': 'application/json',
'Authorization': `Bearer ${apiToken}`
}
});
if (!response.ok) {
console.log(`🛑 Download failed ${taskId} (HTTP ${response.status}):\n${prompt}\n`, await response.text());
break;
}
const taskResponseBody = await response.json();
const { status, artifacts, error, progressRatio, estimatedTimeToStartSeconds } = taskResponseBody;
if (status == 'FAILED') {
console.error(`🛑 FAILED ${taskId} (${error}):\n${prompt}\n`);
break;
}
if (status == 'SUCCEEDED') {
const url = artifacts.at(0).url;
if (url) {
console.log(`✅ Downloading ${url} to ${videoFilename}`);
try {
const videoResponse = await fetch(url);
if (!videoResponse.ok) {
console.error(`⛔ Unable to download ${taskId} (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 ${taskId} status (${status} ${error}):\n${prompt}\n`);
break;
}
console.log(`⌛ ${taskId} status (${status}) and is still in progress (${progressRatio * 100}%, seconds to start ${estimatedTimeToStartSeconds}), 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 runwayml.mjs <API_TOKEN> <EMAIL> [PROMPTS_FILE]');
process.exit(1);
}
console.info('Script v3.1');
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);
console.info(`Configured Runway API accounts (${Object.values(accounts).length}):`, Object.values(accounts).map(a => a.email).join(', '));
if (Object.values(accounts).length <= 0) {
console.error(`⛔ No configured Runway accounts found. Please refer to https://useapi.net/docs/start-here/setup-runwayml`);
process.exit(1);
}
if (!accounts[email]) {
console.error(`⛔ Accounts ${email} not found. Please refer to https://useapi.net/docs/start-here/setup-runwayml`);
process.exit(1);
}
if (accounts[email].error) {
console.error(`⛔ Accounts ${email} has pending error. Please resolve and update account at https://useapi.net/docs/api-runwayml-v1/post-runwayml-accounts-email`);
process.exit(1);
}
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/create endpoint.
// See https://useapi.net/docs/api-runwayml-v1/post-runwayml-videos-create for every model's full parameter set.
const supportedParams = ['model', 'text_prompt', 'firstImage', 'lastImage', 'image', 'aspect_ratio', 'duration', 'seed', 'exploreMode'];
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 { text_prompt, firstImage, lastImage, image } = 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();
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_prompt && !firstImage && !lastImage && !image)
warnings.push(`⚠️ Please specify text_prompt and/or an image (firstImage / lastImage / image). Prompt ${i}`);
await Promise.all([validateImage(firstImage), validateImage(lastImage), validateImage(image)]);
}
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];
while (true) {
const responseCode = await submitVideo(apiToken, email, prompt, i + 1);
if (responseCode == 429)
await sleep(SLEEP_429);
else
if (responseCode == 412) {
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 generations produced through this Runway API, straight from our blog walkthroughs — same videos/create endpoint, model-matched.
Gen-4.5 — text-to-video, 16:9 (no image input)
— from Runway: Gen-4.5 Text-to-Video
Gen-4.5 — image-to-video, 9:16 from a single start frame
— from Runway Gen-4.5: Image-to-Video
Kling 3.0 Pro — kling-3.0-pro, text-to-video with sound, 9:16
Veo 3.1 — veo-3.1, same prompt with sound, 9:16
Sora 2 — sora-2, same prompt with sound, 9:16
The Kling 3.0 Pro, Veo 3.1 and Sora 2 clips above are the same prompt run through three hosted models — from Runway: Unified Videos Endpoint and New Models, which also shows Kling 2.6 I2V and Wan 2.2 Animate.
Seedance 2.0 (via Runway) — seedance-2, image-to-video with real faces, 15s 9:16
— from Seedance 2.0: Using Real Faces
Frequently asked questions
Is there a Runway API? Yes — a few ways. Runway offers an official developer API, and third-party resellers expose Runway too, all billed per generation at developer rates. useapi.net is the consumer-account route: programmatic access to Gen-4.5, Gen-4, Gen-4 Turbo and every model Runway hosts by driving your own Runway account at the website subscription price through a standard REST endpoint.
Which Runway models can I generate through the API? Pick a model per request with the model field on POST /videos/create — gen4.5 (default), gen4, gen4-turbo, plus the hosted veo-3.1, sora-2/sora-2-pro, the Kling family (kling-3.0-pro/standard, kling-2.6-pro/i2v, the kling-o3-* tiers, motion control), wan-2.6-flash/wan-2.2-animate, seedance-2/seedance-2-fast, grok-imagine-1.5 and happyhorse-1.0. See Supported models above.
Can I turn an image into a video (image-to-video)? Yes. Upload the still with POST /assets and pass the returned assetId as imageAssetId1 (start frame). For a first→last transition add imageAssetId2 (end frame) on kling-3.0-pro or veo-3.1 — the Gen-4.x models take a single start frame only. See Image-to-video above.
How much does the Runway API cost? You keep your normal Runway website subscription, plus a flat $15/month to useapi.net for API access to all services. Generations draw from your Runway account’s own credit balance at Runway’s standard rates. The same one subscription covers 10+ other AI services. See Pricing above.
Can I generate images and animate characters too? Yes — the same account and token also reach Frames images (and a dedicated Frames tutorial), the unified Images endpoint for FLUX.2 / Nano Banana / GPT Image / Seedream, Act-Two character animation, and 4K upscale. See Beyond text-to-video above.
My prompt keeps getting rejected — why? Runway’s moderation analyzes both your image and text prompts and fails the task with a moderation message (HTTP 422 on create) when content is judged offensive. Lower the rate of rejected prompts by keeping image and text inputs clearly within Runway’s content guidelines.
Conclusion
Visit our Discord Server or
Telegram Channel for any support questions and concerns.
The full runnable example is in the runway-api GitHub repo.