integrate-uploads

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Integrate Uploads

集成上传功能

PREREQUISITE: Run
+check-compatibility
first. Run
+fetch-api-reference
to load the latest API reference before integrating. Requires
+setup-api-key
for API credentials.
Help users upload local files (images, videos, audio) to Runway's ephemeral storage for use as inputs to generation models.
前置要求: 先运行
+check-compatibility
。集成前请运行
+fetch-api-reference
加载最新的API参考。需要运行
+setup-api-key
配置API凭证。
帮助用户将本地文件(图片、视频、音频)上传到Runway的临时存储,用作生成模型的输入。

When to Use Uploads

什么时候使用上传功能

Use the Uploads API when:
  • The user has a local file (not a public URL) they want to use as input
  • The file exceeds data URI size limits (5 MB for images, 16 MB for video/audio)
  • The file's URL doesn't meet Runway's URL requirements (HTTPS, proper headers, no redirects)
You do NOT need uploads when:
  • The asset is already at a public HTTPS URL with proper headers
  • The asset is small enough for a data URI (< 5 MB image, < 16 MB video)
满足以下条件时请使用上传API:
  • 用户有本地文件(非公共URL)需要作为输入使用
  • 文件超过数据URI大小限制(图片5MB,视频/音频16MB)
  • 文件的URL不符合Runway的URL要求(HTTPS、正确的请求头、无重定向)
满足以下条件时无需使用上传功能:
  • 资源已经存放在符合请求头要求的公共HTTPS URL中
  • 资源足够小,可以使用数据URI(图片<5MB,视频<16MB)

How It Works

工作原理

  1. Request an ephemeral upload slot → get a presigned upload URL and form fields
  2. Upload the file to the presigned URL
  3. Use the returned
    runway://
    URI as input to any generation endpoint
runway://
URIs are valid for 24 hours.
  1. 请求临时上传槽 → 获取预签名上传URL和表单字段
  2. 将文件上传到预签名URL
  3. 使用返回的
    runway://
    URI作为任意生成端点的输入
runway://
URI的有效期为24小时。

SDK Upload (Recommended)

SDK上传(推荐)

Node.js

Node.js

javascript
import RunwayML from '@runwayml/sdk';
import fs from 'fs';

const client = new RunwayML();

// Upload from a file stream
const upload = await client.uploads.createEphemeral(
  fs.createReadStream('/path/to/image.jpg')
);

// Use the runway:// URI in any generation call
const task = await client.imageToVideo.create({
  model: 'gen4.5',
  promptImage: upload.runwayUri,
  promptText: 'The scene comes to life',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();
The Node.js SDK accepts:
  • fs.ReadStream
    — file streams
  • File
    objects — from web APIs
  • Blob
    objects
  • Buffer
    /
    ArrayBuffer
    / typed arrays
  • Response
    objects — from
    fetch()
  • Async iterables
javascript
import RunwayML from '@runwayml/sdk';
import fs from 'fs';

const client = new RunwayML();

// Upload from a file stream
const upload = await client.uploads.createEphemeral(
  fs.createReadStream('/path/to/image.jpg')
);

// Use the runway:// URI in any generation call
const task = await client.imageToVideo.create({
  model: 'gen4.5',
  promptImage: upload.runwayUri,
  promptText: 'The scene comes to life',
  ratio: '1280:720',
  duration: 5
}).waitForTaskOutput();
Node.js SDK支持的输入类型:
  • fs.ReadStream
    — 文件流
  • File
    对象 — 来自Web API
  • Blob
    对象
  • Buffer
    /
    ArrayBuffer
    / 类型化数组
  • Response
    对象 — 来自
    fetch()
  • 异步可迭代对象

Python

Python

python
from runwayml import RunwayML
from pathlib import Path

client = RunwayML()
python
from runwayml import RunwayML
from pathlib import Path

client = RunwayML()

Upload from a file path

Upload from a file path

upload = client.uploads.create_ephemeral( Path('/path/to/image.jpg') )
upload = client.uploads.create_ephemeral( Path('/path/to/image.jpg') )

Use the runway:// URI

Use the runway:// URI

task = client.image_to_video.create( model='gen4.5', prompt_image=upload.runway_uri, prompt_text='The scene comes to life', ratio='1280:720', duration=5 ).wait_for_task_output()

The Python SDK accepts:
- `pathlib.Path` objects
- `IOBase` objects (file-like objects)
- Two-tuples of `(filename, content)`
task = client.image_to_video.create( model='gen4.5', prompt_image=upload.runway_uri, prompt_text='The scene comes to life', ratio='1280:720', duration=5 ).wait_for_task_output()

Python SDK支持的输入类型:
- `pathlib.Path` 对象
- `IOBase` 对象(类文件对象)
- 二元组 `(文件名, 内容)`

REST API Upload (Manual)

REST API上传(手动)

If not using the SDK, the upload flow has three steps:
如果不使用SDK,上传流程分为三步:

Step 1: Create an upload slot

步骤1:创建上传槽

javascript
const response = await fetch('https://api.dev.runwayml.com/v1/uploads', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    filename: 'image.jpg',
    type: 'ephemeral'
  })
});

const { uploadUrl, fields, runwayUri } = await response.json();
javascript
const response = await fetch('https://api.dev.runwayml.com/v1/uploads', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    filename: 'image.jpg',
    type: 'ephemeral'
  })
});

const { uploadUrl, fields, runwayUri } = await response.json();

Step 2: Upload the file using the presigned URL

步骤2:使用预签名URL上传文件

javascript
const formData = new FormData();

// Add all presigned form fields first
for (const [key, value] of Object.entries(fields)) {
  formData.append(key, value);
}

// Add the file last
formData.append('file', fileBuffer, 'image.jpg');

await fetch(uploadUrl, {
  method: 'POST',
  body: formData
});
javascript
const formData = new FormData();

// Add all presigned form fields first
for (const [key, value] of Object.entries(fields)) {
  formData.append(key, value);
}

// Add the file last
formData.append('file', fileBuffer, 'image.jpg');

await fetch(uploadUrl, {
  method: 'POST',
  body: formData
});

Step 3: Use the
runway://
URI

步骤3:使用
runway://
URI

javascript
const task = await fetch('https://api.dev.runwayml.com/v1/image_to_video', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'gen4.5',
    promptImage: runwayUri,
    promptText: 'Animate this scene',
    ratio: '1280:720',
    duration: 5
  })
});
javascript
const task = await fetch('https://api.dev.runwayml.com/v1/image_to_video', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.RUNWAYML_API_SECRET}`,
    'X-Runway-Version': '2024-11-06',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    model: 'gen4.5',
    promptImage: runwayUri,
    promptText: 'Animate this scene',
    ratio: '1280:720',
    duration: 5
  })
});

Upload Constraints

上传限制

ConstraintValue
Minimum file size512 bytes
Maximum file size200 MB
URI validity24 hours
Requires creditsYes (must have purchased credits)
限制项取值
最小文件大小512 字节
最大文件大小200 MB
URI有效期24 小时
是否需要积分是(必须已购买积分)

Integration Pattern

集成示例

Express.js — Upload Endpoint with File Generation

Express.js — 带文件生成的上传端点

javascript
import RunwayML from '@runwayml/sdk';
import express from 'express';
import multer from 'multer';

const client = new RunwayML();
const app = express();
const upload = multer({ storage: multer.memoryStorage() });

app.post('/api/image-to-video', upload.single('image'), async (req, res) => {
  try {
    // Upload the user's file to Runway
    const runwayUpload = await client.uploads.createEphemeral(req.file.buffer);

    // Use the uploaded file for video generation
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: runwayUpload.runwayUri,
      promptText: req.body.prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    res.json({ videoUrl: task.output[0] });
  } catch (error) {
    console.error('Generation failed:', error);
    res.status(500).json({ error: error.message });
  }
});
javascript
import RunwayML from '@runwayml/sdk';
import express from 'express';
import multer from 'multer';

const client = new RunwayML();
const app = express();
const upload = multer({ storage: multer.memoryStorage() });

app.post('/api/image-to-video', upload.single('image'), async (req, res) => {
  try {
    // Upload the user's file to Runway
    const runwayUpload = await client.uploads.createEphemeral(req.file.buffer);

    // Use the uploaded file for video generation
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: runwayUpload.runwayUri,
      promptText: req.body.prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    res.json({ videoUrl: task.output[0] });
  } catch (error) {
    console.error('Generation failed:', error);
    res.status(500).json({ error: error.message });
  }
});

Next.js — Upload + Generate

Next.js — 上传+生成

typescript
// app/api/image-to-video/route.ts
import RunwayML from '@runwayml/sdk';
import { NextRequest, NextResponse } from 'next/server';

const client = new RunwayML();

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const imageFile = formData.get('image') as File;
  const prompt = formData.get('prompt') as string;

  try {
    // Upload file to Runway
    const upload = await client.uploads.createEphemeral(imageFile);

    // Generate video from the uploaded image
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: upload.runwayUri,
      promptText: prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    return NextResponse.json({ videoUrl: task.output[0] });
  } catch (error) {
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Failed' },
      { status: 500 }
    );
  }
}
typescript
// app/api/image-to-video/route.ts
import RunwayML from '@runwayml/sdk';
import { NextRequest, NextResponse } from 'next/server';

const client = new RunwayML();

export async function POST(request: NextRequest) {
  const formData = await request.formData();
  const imageFile = formData.get('image') as File;
  const prompt = formData.get('prompt') as string;

  try {
    // Upload file to Runway
    const upload = await client.uploads.createEphemeral(imageFile);

    // Generate video from the uploaded image
    const task = await client.imageToVideo.create({
      model: 'gen4.5',
      promptImage: upload.runwayUri,
      promptText: prompt || 'Animate this image',
      ratio: '1280:720',
      duration: 5
    }).waitForTaskOutput();

    return NextResponse.json({ videoUrl: task.output[0] });
  } catch (error) {
    return NextResponse.json(
      { error: error instanceof Error ? error.message : 'Failed' },
      { status: 500 }
    );
  }
}

FastAPI — Upload + Generate

FastAPI — 上传+生成

python
from fastapi import FastAPI, UploadFile, Form, HTTPException
from runwayml import RunwayML

app = FastAPI()
client = RunwayML()

@app.post("/api/image-to-video")
async def image_to_video(image: UploadFile, prompt: str = Form("Animate this image")):
    try:
        # Upload to Runway
        content = await image.read()
        upload = client.uploads.create_ephemeral((image.filename, content))

        # Generate video
        task = client.image_to_video.create(
            model="gen4.5",
            prompt_image=upload.runway_uri,
            prompt_text=prompt,
            ratio="1280:720",
            duration=5
        ).wait_for_task_output()

        return {"video_url": task.output[0]}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
python
from fastapi import FastAPI, UploadFile, Form, HTTPException
from runwayml import RunwayML

app = FastAPI()
client = RunwayML()

@app.post("/api/image-to-video")
async def image_to_video(image: UploadFile, prompt: str = Form("Animate this image")):
    try:
        # Upload to Runway
        content = await image.read()
        upload = client.uploads.create_ephemeral((image.filename, content))

        # Generate video
        task = client.image_to_video.create(
            model="gen4.5",
            prompt_image=upload.runway_uri,
            prompt_text=prompt,
            ratio="1280:720",
            duration=5
        ).wait_for_task_output()

        return {"video_url": task.output[0]}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Tips

注意事项

  • Always upload local files before passing them to generation endpoints. Don't try to pass local file paths — they won't work.
  • runway://
    URIs expire after 24 hours.
    If you need to re-use an asset, upload it again.
  • The SDK handles the presigned URL flow automatically — prefer the SDK over manual REST calls.
  • For models requiring image/video input (image-to-video, video-to-video, character performance), upload the asset first, then pass the
    runway://
    URI.
  • Maximum 200 MB per file via uploads — larger than URL (16 MB) or data URI (5 MB) limits.
  • 传递给生成端点前务必先上传本地文件,不要尝试传递本地文件路径——它们无法被识别。
  • runway://
    URI 24小时后过期
    ,如果需要重复使用资源,请重新上传。
  • SDK会自动处理预签名URL流程——优先使用SDK而非手动调用REST接口。
  • 对于需要图片/视频输入的模型(图生视频、视频生视频、角色表演),先上传资源,再传递
    runway://
    URI。
  • 单个上传文件最大支持200MB——比URL(16MB)和数据URI(5MB)的限制更高。