.NET MVC CORE

Integrating Runway ML API in .NET: a complete guide

Runway ML is one of the leading AI video generation platforms. It gives developers a REST API to generate videos from text prompts or images — no GPU infrastructure required. This guide covers everything you need to integrate Runway ML into a .NET application: what models are available, how pricing works, what the API flow looks like, and how to handle long-running video generation jobs.

J
Joynal Abedin
82
Integrating Runway ML API in .NET: a complete guide

About Runway ML

Runway AI, Inc. was founded in 2018 in New York, USA. They build generative AI tools for creative professionals — video, image, and audio generation. Their flagship product is the Gen-series video generation model, exposed via a REST API at api.dev.runwayml.com/v1.

The API is production-ready and used by studios, startups, and indie developers globally. It authenticates via a Bearer token in the Authorization header and requires the X-Runway-Version header (e.g. 2024-11-06) on every request.


Available models

Runway provides three current model variants under the seedance2 family. The older gen3a_turbo is deprecated — it returns 403 errors on /text_to_video and 400 errors on /image_to_video. Do not use it in new projects.

Model Speed Quality Cost Best for
seedance2 Slow Highest Most Ad production, portfolio, final renders
seedance2_fast Balanced High Medium Most applications — recommended default
seedance2_mini Fastest Good Lowest Previews, prototyping, high-volume workflows

All three models support:

  • Text to video and image to video
  • Multi-image input (up to 9 images)
  • Optional audio generation
  • Duration: 5–15 seconds
  • Aspect ratios: 21:9, 16:9, 4:3, 1:1, 3:4, 9:16
  • Output resolutions: 480p, 720p, 1080p

Aspect ratios and pixel dimensions

Runway does not accept generic ratio strings like 16:9 directly. You must pass exact pixel dimension strings (e.g. 1280:720). The resolution determines which dimensions are valid.

Ratio 480p 720p 1080p
21:9 992:432 1470:630 2206:946
16:9 864:496 1280:720 1920:1080
4:3 752:560 1112:834 1664:1248
1:1 640:640 960:960 1440:1440
3:4 560:752 834:1112 1248:1664
9:16 496:864 720:1280 1080:1920

In your code, implement a mapping function that takes (aspectRatio, outputResolution) and returns the correct pixel string. Passing an invalid or unrecognized value results in a 400 error from the API.


Pricing and credits

Runway charges in credits. You purchase credit packs, and each generation consumes credits based on model, duration, resolution, and whether audio is enabled.

Plan Monthly credits Price Best for
Starter ~125 credits ~$15/mo Hobby / testing
Standard ~625 credits ~$35/mo Small apps
Pro ~2,250 credits ~$95/mo Production apps
Unlimited Pooled team ~$195/mo Teams / studios

Always verify current pricing at runwayml.com/pricing before estimating production costs. Runway adjusts rates as models evolve.

Approximate credit cost per video

Generation Approx. credits
seedance2_mini — 5 sec, 720p, no audio ~5 credits
seedance2_fast — 5 sec, 720p, no audio ~10 credits
seedance2_fast — 10 sec, 720p, with audio ~25 credits
seedance2 — 15 sec, 1080p, with audio ~75 credits
1 credit ~$0.04–$0.07 USD

Audio generation adds roughly 1 credit per second of video. A 10-second video with audio costs approximately 10 additional credits on top of the base generation cost. If cost is a concern, offer users an audio toggle and default it to false.


How the API works

Runway's video generation API is asynchronous. You do not receive a video file immediately. Instead:

  1. POST to /text_to_video or /image_to_video with your parameters
  2. Receive a task_id in the response
  3. Poll GET /tasks/{task_id} repeatedly until status changes
  4. When status is SUCCEEDED, download the video from the output URL
  5. Re-host the video in your own storage — Runway's output URLs are temporary

Task status values

Status Meaning What to do
PENDING Queued, not yet started Keep polling
RUNNING Generation in progress Track progress percentage, keep polling
SUCCEEDED Video is ready Download from output URL
FAILED Generation failed Read error message, surface to user

Key request fields

Field Type Required Notes
model string Yes seedance2 / seedance2_fast / seedance2_mini
promptText string Yes Describe the video content
promptImage string or array Image-to-video only Single = base64 string. Multiple = array of {"uri":"data:..."} objects
ratio string Yes Pixel dimensions, e.g. 1280:720
duration int Yes 5–15 seconds
audio bool No Default false. Adds background audio; increases cost

Important: For image-to-video with a single image, pass promptImage as a plain base64 data URI string. For multiple images (up to 9), pass an array of objects: [{"uri":"data:image/jpeg;base64,..."}]. Passing plain strings inside an array returns a 400 error.


Integration architecture in .NET

In an ASP.NET Core application, use a layered approach:

1. Service layer — IRunwayMLService

Encapsulate all Runway HTTP calls behind an interface. Register it in DI. Methods needed:

  • CreateTaskAsync(request, endpoint, cancellationToken) — POST to Runway, returns task ID
  • GetTaskStatusAsync(taskId, cancellationToken) — GET task status and progress
  • DownloadVideoAsync(videoUrl, cancellationToken) — download completed video bytes

2. Controller layer — VideoGenerationController

Accept user input via [FromForm], validate parameters, call the service, and stream progress back to the client using Server-Sent Events (SSE).

3. Storage layer — Cloudflare R2 or S3

Once generation completes, download the video from Runway's temporary URL and store it in your own object storage. Never return Runway's output URL directly to clients — it expires.

4. Database layer — EF Core

Persist the task ID, status, and final video URL. Poll and update the record as the task progresses. Index on RunwayTaskId (unique) and UserId for fast lookups.


SSE polling strategy

Video generation takes 30 seconds to several minutes. A simple HTTP response will time out. Use Server-Sent Events to stream live progress to the client without holding a blocking connection.

Adaptive polling is the key to avoiding the most common failure — socket timeout when progress stalls at ~90–95%:

Setting Value Why
Normal poll interval 2,000 ms Avoids rate limits during slow early progress
Fast poll interval 800 ms Reduces perceived lag near completion
Fast poll threshold ≥ 80% progress Progress near the end stalls if polled slowly
Max poll attempts 300 10-minute safety ceiling
HttpClient timeout 10 minutes Must exceed max poll duration

Only write to the database when status or progress actually changes — avoid unnecessary writes on every poll iteration.


Environment variables you need

Never hardcode secrets. Store all credentials as environment variables and read them at runtime.

Variable Where to get it
RUNWAY_API_KEY Runway dashboard → API Keys → Create new key (needs video generation permissions)
R2_ACCESS_KEY_ID Cloudflare dashboard → R2 → API Tokens → Create token with Object Read/Write
R2_SECRET_ACCESS_KEY Generated alongside the access key — copy immediately, shown only once
R2_BUCKET_NAME Cloudflare R2 → Buckets → your bucket name
R2_ACCOUNT_ID Cloudflare dashboard → right sidebar → Account ID
ConnectionStrings__DefaultConnection Your SQL Server / Azure SQL connection string

In development, use appsettings.Development.json or dotnet user-secrets. In production (Azure App Service, etc.), set these as Application Settings environment variables. Never commit secrets to source control.


Common errors and how to fix them

Error Cause Fix
400 — promptImage undefined Calling /image_to_video without sending promptImage Always include at least one base64 image for image-to-video
400 — promptImage array items must be objects Passing ["data:image/..."] strings instead of objects Use [{"uri":"data:image/..."}] format
400 — ratio not recognized Passing a human-readable ratio like 16:9 Use exact pixel strings from the dimension table (e.g. 1280:720)
400 — resolution unrecognized key Sending a resolution field in the request body Remove it — resolution is encoded in the ratio pixel dimensions
403 — model not available Using deprecated gen3a_turbo Switch to the seedance2 model family
SSE socket timeout at ~95% HttpClient timeout too short; polling too slow near completion Raise HttpClient timeout to 10 min; use adaptive fast polling at ≥80%

Implementation checklist

  1. Register HttpClient with a 10-minute timeout in Program.cs for the Runway service
  2. Read the API key from environment variables — never from committed config files
  3. Validate duration is between 5 and 15 seconds — Runway rejects values outside this range
  4. Map aspect ratio + resolution to the correct pixel dimension string before calling the API
  5. Implement adaptive SSE polling — 2s normally, 0.8s when progress ≥ 80%
  6. Download and re-host the video in your own R2/S3 bucket — Runway output URLs expire
  7. Persist task state in your database — only write when status or progress actually changes
  8. Handle multi-image input correctly — 1 image = string, 2–9 images = array of {"uri":"..."} objects
  9. Offer an audio toggle and clearly communicate the added credit cost to users
  10. Index your database on RunwayTaskId (unique) and UserId for efficient polling queries

Which model should you use?

For most applications, start with seedance2_fast. It strikes the right balance between speed, quality, and cost. Upgrade to seedance2 when users need maximum quality (ad production, portfolio exports). Use seedance2_mini for draft previews or high-volume non-critical workflows.

Recommended default configuration: seedance2_fast · 720p · 5 seconds · audio: false

This gives a solid user experience at roughly 10 credits per video (~$0.50–$0.70 USD), and users can opt into longer duration, higher resolution, or audio when they need it.


Runway ML's API evolves quickly. Always verify model names, pricing, and endpoint paths against the official documentation at docs.dev.runwayml.com before shipping to production.

J

Written by Joynal Abedin

Passionate about technology, code, and sharing knowledge.

0 Comments

Leave a Comment