Upscale a video to 4K with Topaz AI

May 15, 2026

Table of contents

  1. Constraints
  2. Request Headers
  3. Request Body
  4. Responses
  5. Model
  6. Examples
  7. Try It

Upscale a video to 4K using Topaz AI. Output preserves the source aspect ratio and bumps the longer dimension up to 4K class (e.g. a 1280×720 source → 4096×2304, a 1080×1920 source → 2160×3840).

The input is a videoAssetId. Two common ways to obtain one:

  • Upscale a video you generated — pass the assetId from any video task: videos/create outputs (Kling, Sora, Veo, Wan, Seedance, HappyHorse, Gen-4.x), gen4-video, or any other Runway video task. Look it up later via GET /assets/?mediaType=video.
  • Upscale an uploaded video — upload your own file via POST /assets and use the returned assetId.
Constraints
Constraint Value
Max source duration 40 seconds
Source media type video
Output 4K (source aspect ratio preserved)
Model Topaz AI (only option)
Billing 2 credits/second, or free with exploreMode on Runway Unlimited plan

https://api.useapi.net/v1/runwayml/videos/upscale

Request Headers
Authorization: Bearer {API token}
Content-Type: application/json
Request Body
{
    "videoAssetId": "Required assetId of any video asset to upscale",
    "exploreMode": true,
    "replyUrl": "Place your call back URL here",
    "replyRef": "Place your reference id here",
    "maxJobs": 5
}
  • videoAssetId is required. The video asset to upscale. Use GET /assets/?mediaType=video to list video assets, or pass through any assetId returned by videos/create, gen4-video, POST /assets, etc. The account that owns the asset is charged for the upscale — no email parameter is needed.

  • exploreMode is optional. Set to true if you have a Runway Unlimited plan and wish to execute relaxed generation. You are not charged credits for Explore mode generations.

  • replyUrl is optional, if not provided value from useapi.net account will be used. Place here your callback URL. API will call the provided replyUrl once Runway task completed or failed. Maximum length 1024 characters. We recommend using sites like webhook.site to test callback URL functionality.

  • replyRef is optional, place here your reference id which will be stored and returned along with this Runway task response / result. Maximum length 1024 characters.

  • maxJobs is optional, if not provided the value configured for the account owning the video asset will be used. Valid range: 1…10. See Setup Runway for details on per-account concurrency.

Responses
  • 200 OK

    Use returned taskId to retrieve task status and results using GET /tasks/taskId. The upscaled video url can be found in the artifacts array of the task with the status SUCCEEDED.

    If you specify the optional parameter replyUrl the API will call the provided replyUrl with task progress updates until the task is complete or fails.

    {
        "taskId": "user:user_id-runwayml:account_email-task:task_uuid",
        "id": "<uuid>",
        "name": "Upscaled <source video name>",
        "image": null,
        "createdAt": "2026-05-15T20:10:08.838Z",
        "updatedAt": "2026-05-15T20:10:08.838Z",
        "taskType": "harrods",
        "options": {
            "name": "Upscaled <source video name>",
            "parent_asset_group_id": "<uuid>",
            "creationSource": "apps",
            "creationSourceAppId": "upscale-video",
            "asset_id": "<source video uuid>",
            "exploreMode": true,
            "recordingEnabled": true
        },
        "status": "THROTTLED",
        "error": null,
        "progressText": null,
        "progressRatio": "0",
        "estimatedTimeToStartSeconds": 0,
        "artifacts": [],
        "sharedAsset": null,
        "sourceAssetId": null,
        "replyUrl": "https://webhook.site/abc",
        "replyRef": "<your optional reference id>",
        "code": 200
    }
    

    On completion, polling GET /tasks/taskId returns the artifact with the 4K dimensions and a signed download URL:

    {
        "status": "SUCCEEDED",
        "progressRatio": "1",
        "artifacts": [
            {
                "id": "<uuid>",
                "assetId": "user:user_id-runwayml:account_email-asset:<uuid>",
                "filename": "<source name> 4K.mp4",
                "url": "https://dnznrvs05pmza.cloudfront.net/<uuid>.mp4?_jwt=...",
                "fileSize": "14173798",
                "metadata": {
                    "frameRate": 50,
                    "duration": 8,
                    "dimensions": [4096, 2304],
                    "size": { "width": 4096, "height": 2304 }
                }
            }
        ]
    }
    
  • 400 Bad Request

    Returned when videoAssetId is missing or malformed, the referenced asset is not a video, or the source video exceeds the 40-second maximum:

    {
      "error": "videoAssetId duration (52.30s) exceeds maximum 40s for video upscale",
      "code": 400
    }
    
  • 401 Unauthorized

    {
      "error": "Unauthorized",
      "code": 401
    }
    
  • 404 Not Found

    {
        "error": "Unable to retrieve assetId <uuid> (Not found.)",
        "code": 404
    }
    
  • 412 Insufficient credits

    You do not have enough credits to run this task. Set exploreMode: true if you have a Runway Unlimited plan.

    {
        "error": "You do not have enough credits to run this task."
    }
    
  • 429 Too Many Requests

    Wait in a loop for at least 10..30 seconds and retry again.

    {
        "error": "Account <Runway account email> is busy executing <Account maxJobs> tasks",
        "runningTasks": {
            "<Runway account email>": [
                {
                    "email": "<Runway account email>",
                    "taskId": "user:user_id-runwayml:account_email-task:task_uuid",
                    "id": "<uuid>",
                    "replyUrl": "<replyUrl if provided>",
                    "replyRef": "<replyRef if provided>"
                }
            ]
        },
        "code": 429
    }
    
Model
{ // TypeScript, all fields are optional
    id: string
    taskId: string
    name: string
    image: any
    createdAt: string
    updatedAt: string
    taskType: string
    options: {
        name: string
        asset_id: string
        creationSource: 'apps'
        creationSourceAppId: 'upscale-video'
        parent_asset_group_id: string
        exploreMode: boolean
        recordingEnabled: boolean
    }
    status: string
    error: {
      errorMessage: string
      reason: string
      message: string
      moderation_category: string
      tally_asimov: boolean
    }
    progressText: string
    progressRatio: number
    estimatedTimeToStartSeconds: number
    artifacts: {
        id: string
        assetId: string
        filename: string
        url: string
        fileSize: string
        previewUrls: string[]
        metadata: {
            frameRate: number
            duration: number
            dimensions: [number, number]
            size: { width: number, height: number }
        }
    }[]
    sharedAsset: any
    sourceAssetId: any
    code: number
    replyUrl: string
    replyRef: string
}
Examples
  • curl -H "Accept: application/json" \
         -H "Content-Type: application/json" \
         -H "Authorization: Bearer …" \
         -X POST "https://api.useapi.net/v1/runwayml/videos/upscale" \
         -d '{"videoAssetId": "…", "exploreMode": true }'
    
  • const videoAssetId = "assetId of video asset";
    const apiUrl = `https://api.useapi.net/v1/runwayml/videos/upscale`;
    const token = "API token";
    const data = {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${token}`,
        'Content-Type': 'application/json' }
    };
    data.body = JSON.stringify({
      videoAssetId,
      exploreMode: true
    });
    const response = await fetch(apiUrl, data);
    const result = await response.json();
    console.log("response", {response, result});
    
  • import requests
    videoAssetId = "assetId of video asset"
    apiUrl = f"https://api.useapi.net/v1/runwayml/videos/upscale"
    token = "API token"
    headers = {
        "Content-Type": "application/json",
        "Authorization" : f"Bearer {token}"
    }
    body = {
        "videoAssetId": f"{videoAssetId}",
        "exploreMode": True
    }
    response = requests.post(apiUrl, headers=headers, json=body)
    print(response, response.json())
    
Try It