Skip to content
Developers
API docs / Features

MAKEUGC PLATFORM API · DOCS V2

Video Upscale

Quote and upscale owned videos with Topaz, with billing tracked per attempt.

Workflow

  1. Identify the source video's id, project_id and video_type.
  2. Request a quote and review data.quote.credits.
  3. Submit the same model and source options and save billing_id.
  4. Poll the billing attempt until completed, failed or refunded.
precision models: Proteus.
generative models: Starlight Precise 2.6, Starlight HQ, Starlight Mini, Starlight Sharp, Starlight Fast 2.
creative models: Astra 2.
Send X-Api-Key on every MakeUGC request. POST operations require an active paid subscription and a positive credit balance; custom voice creation also requires a plan with custom voices.
Requests are strict JSON: unknown fields, user_id and webhook_url are rejected. Use polling for jobs; these endpoints do not send webhooks.
The outer status boolean indicates request success. Most jobs use data.status: processing, completed or failed; Upscale documents its own statuses. Poll every 5–10 seconds and require a non-empty result URL (or voice_id) before using output.
API credit units × 100 = website display credits. A timeout, network error or 5xx may occur after acceptance: do not automatically resubmit a paid operation. If submission_unknown is true, check the project or contact support with x-request-id; reserved credits remain held until the result is resolved.

Example IDs and media URLs are placeholders. Replace them with values from your account and accessible media files.

Quote an upscale #

POST /upscale/quote

Probe an owned video and estimate the credit cost without submitting an upscale job.

Source probing can take up to 370 seconds. Use a client timeout of at least 420 seconds. The quote is informational; submission obtains its own current quote.
Source must be at most 300 seconds and 60 fps. Upscale factor must be 1–4, with output at most 2160 pixels on the short side and 3840 on the long side. Unsupported source geometry is rejected.

Request body

Parameter Description
video_id
string
Required
video id input.

Allowed: At least 1 characters; Up to 256 characters

project_id
string
Required
project id input.

Allowed: At least 1 characters; Up to 256 characters

video_type
string
Required
video type input.

Allowed: video | product-in-hand | b-roll | gestures | wan-animate | sora2 | scenes | seedance_2_video | seedance_25_video | grok_video | minimax_video | veo3_extend | prompt_studio_video | template_ads | platform_background_removal

model_family
string
Required
model family input.

Allowed: precision | generative | creative

model
string
Required
model input.

Allowed: At least 1 characters; Up to 256 characters

target_resolution
string
Required
target resolution input.

Allowed: 720p | 1080p | 1440p | 2160p

Request example

cURL
curl --fail-with-body --max-time 420 -X POST "https://app.makeugc.ai/api/platform/upscale/quote" \
  -H "X-Api-Key: $MAKEUGC_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "video_id": "video_123",
  "project_id": "project_123",
  "video_type": "seedance_25_video",
  "model_family": "precision",
  "model": "Proteus",
  "target_resolution": "1080p"
}'
JavaScript
// Run on your server with Node.js 20+.
const apiKey = process.env.MAKEUGC_API_KEY;
if (!apiKey) throw new Error("Set MAKEUGC_API_KEY first");

const response = await fetch("https://app.makeugc.ai/api/platform/upscale/quote", {
  method: "POST",
  headers: {
    "X-Api-Key": apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "video_id": "video_123",
  "project_id": "project_123",
  "video_type": "seedance_25_video",
  "model_family": "precision",
  "model": "Proteus",
  "target_resolution": "1080p"
}),
  signal: AbortSignal.timeout(420000),
});
const text = await response.text();
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${text} (request ${response.headers.get("x-request-id")})`);
}
const result = JSON.parse(text);
console.log(result);
Python
# Install the requests package before running.
import os
import requests

payload = {
    "video_id": "video_123",
    "project_id": "project_123",
    "video_type": "seedance_25_video",
    "model_family": "precision",
    "model": "Proteus",
    "target_resolution": "1080p"
}

response = requests.post(
    "https://app.makeugc.ai/api/platform/upscale/quote",
    headers={"X-Api-Key": os.environ["MAKEUGC_API_KEY"]},
    json=payload,
    timeout=420,
)
if not response.ok:
    raise RuntimeError(f"HTTP {response.status_code}: {response.text} "
                       f"(request {response.headers.get('x-request-id')})")
print(response.json())

200 response example

JSON response
{
  "status": true,
  "data": {
    "success": true,
    "videoId": "video_123",
    "modelFamily": "precision",
    "model": "Proteus",
    "upscaleFactor": 1.5,
    "metadata": {
      "width": 720,
      "height": 1280,
      "duration": 10,
      "fps": 30,
      "frames": 300
    },
    "quote": {
      "credits": 1.25
    }
  }
}

All requests require X-Api-Key. See errors & retries for unsuccessful responses.

Submit an upscale #

POST /upscale/generate

Upscale an existing video owned by your account and save data.billing_id for this attempt.

Upscale replaces the output URL on the existing video record. Save the original file first if you need both versions.
The service handles charging and refunds. This operation is not idempotent: do not submit again while an attempt is active.

Request body

Parameter Description
video_id
string
Required
video id input.

Allowed: At least 1 characters; Up to 256 characters

project_id
string
Required
project id input.

Allowed: At least 1 characters; Up to 256 characters

video_type
string
Required
video type input.

Allowed: video | product-in-hand | b-roll | gestures | wan-animate | sora2 | scenes | seedance_2_video | seedance_25_video | grok_video | minimax_video | veo3_extend | prompt_studio_video | template_ads | platform_background_removal

model_family
string
Required
model family input.

Allowed: precision | generative | creative

model
string
Required
model input.

Allowed: At least 1 characters; Up to 256 characters

target_resolution
string
Required
target resolution input.

Allowed: 720p | 1080p | 1440p | 2160p

Request example

cURL
curl --fail-with-body --max-time 120 -X POST "https://app.makeugc.ai/api/platform/upscale/generate" \
  -H "X-Api-Key: $MAKEUGC_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
  "video_id": "video_123",
  "project_id": "project_123",
  "video_type": "seedance_25_video",
  "model_family": "precision",
  "model": "Proteus",
  "target_resolution": "1080p"
}'
JavaScript
// Run on your server with Node.js 20+.
const apiKey = process.env.MAKEUGC_API_KEY;
if (!apiKey) throw new Error("Set MAKEUGC_API_KEY first");

const response = await fetch("https://app.makeugc.ai/api/platform/upscale/generate", {
  method: "POST",
  headers: {
    "X-Api-Key": apiKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
  "video_id": "video_123",
  "project_id": "project_123",
  "video_type": "seedance_25_video",
  "model_family": "precision",
  "model": "Proteus",
  "target_resolution": "1080p"
}),
  signal: AbortSignal.timeout(120000),
});
const text = await response.text();
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${text} (request ${response.headers.get("x-request-id")})`);
}
const result = JSON.parse(text);
console.log(result);
Python
# Install the requests package before running.
import os
import requests

payload = {
    "video_id": "video_123",
    "project_id": "project_123",
    "video_type": "seedance_25_video",
    "model_family": "precision",
    "model": "Proteus",
    "target_resolution": "1080p"
}

response = requests.post(
    "https://app.makeugc.ai/api/platform/upscale/generate",
    headers={"X-Api-Key": os.environ["MAKEUGC_API_KEY"]},
    json=payload,
    timeout=120,
)
if not response.ok:
    raise RuntimeError(f"HTTP {response.status_code}: {response.text} "
                       f"(request {response.headers.get('x-request-id')})")
print(response.json())

200 response example

JSON response
{
  "status": true,
  "data": {
    "id": "video_123",
    "billing_id": "billing_123",
    "project_id": "project_123",
    "status": "processing"
  }
}

All requests require X-Api-Key. See errors & retries for unsuccessful responses.

Get upscale attempt status #

GET /upscale/status

Poll using billing_id and the same source video identifiers. video_url is returned only after this billing attempt completes.

Upscale uses preparing and charged as in-progress statuses; completed, refunded and failed are terminal. A video record may retain its original URL while upscale is running. Always poll this endpoint instead of the original generation status.

Parameters

Parameter Description
video_id
string · query
Required
video id input.

Allowed: At least 1 characters; Up to 256 characters

project_id
string · query
Required
project id input.

Allowed: At least 1 characters; Up to 256 characters

video_type
string · query
Required
video type input.

Allowed: video | product-in-hand | b-roll | gestures | wan-animate | sora2 | scenes | seedance_2_video | seedance_25_video | grok_video | minimax_video | veo3_extend | prompt_studio_video | template_ads | platform_background_removal

billing_id
string · query
Required
billing id input.

Allowed: At least 1 characters; Up to 256 characters

Request example

cURL
curl --fail-with-body --max-time 120 -X GET "https://app.makeugc.ai/api/platform/upscale/status?video_id=VIDEO_ID&project_id=PROJECT_ID&video_type=VIDEO_TYPE&billing_id=BILLING_ID" \
  -H "X-Api-Key: $MAKEUGC_API_KEY"
JavaScript
// Run on your server with Node.js 20+.
const apiKey = process.env.MAKEUGC_API_KEY;
if (!apiKey) throw new Error("Set MAKEUGC_API_KEY first");

const response = await fetch("https://app.makeugc.ai/api/platform/upscale/status?video_id=VIDEO_ID&project_id=PROJECT_ID&video_type=VIDEO_TYPE&billing_id=BILLING_ID", {
  method: "GET",
  headers: {
    "X-Api-Key": apiKey,
  },
  signal: AbortSignal.timeout(120000),
});
const text = await response.text();
if (!response.ok) {
  throw new Error(`HTTP ${response.status}: ${text} (request ${response.headers.get("x-request-id")})`);
}
const result = JSON.parse(text);
console.log(result);
Python
# Install the requests package before running.
import os
import requests

response = requests.get(
    "https://app.makeugc.ai/api/platform/upscale/status?video_id=VIDEO_ID&project_id=PROJECT_ID&video_type=VIDEO_TYPE&billing_id=BILLING_ID",
    headers={"X-Api-Key": os.environ["MAKEUGC_API_KEY"]},
    timeout=120,
)
if not response.ok:
    raise RuntimeError(f"HTTP {response.status_code}: {response.text} "
                       f"(request {response.headers.get('x-request-id')})")
print(response.json())

200 response example

JSON response
{
  "status": true,
  "data": {
    "id": "video_123",
    "billing_id": "billing_123",
    "status": "completed",
    "video_url": "https://your-cdn.example/upscaled.mp4",
    "credits_charged": 1.25,
    "credits_refunded": 0,
    "error": null
  }
}

All requests require X-Api-Key. See errors & retries for unsuccessful responses.