API Get key

StaglightTools

Merge clips

Joins 2 to 12 clips into one video in 9:16, 4:5, 1:1 or 16:9.

Price
10 crper run
Usual time
≈ 45 s
Model id
edit.merge

Playground

Playground

Clips *

Sign in to upload a file.

Format
Fit

Music

Sign in to upload a file.

Voiceover

Sign in to upload a file.

Sign up to run it

Change the settings: the price and the code follow. You need an account to run it.

edit.merge
Shape
keep, 9:16, 4:5, 1:1, 16:9
Takes
Video, Audio

No example of this model yet. These are its real settings.

# 0. Upload your file first and put the id it prints in params.
curl -s -X POST https://staglight.ai/api/v1/uploads \
  -H "Authorization: Bearer $STAGLIGHT_API_KEY" -F file=@your-file | jq -r .id

# 1. Create the job. It is charged once and refunded if it fails.
JOB_ID=$(curl -s -X POST https://staglight.ai/api/v1/jobs \
  -H "Authorization: Bearer $STAGLIGHT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "op": "edit.merge",
    "params": {
      "clips": [
        "med_your_upload_id"
      ],
      "aspect": "9:16"
    },
    "max_credits": 10
  }' | jq -r .id)

# 2. Poll until it finishes. Each call waits up to 30 seconds.
while :; do
  JOB=$(curl -s "https://staglight.ai/api/v1/jobs/$JOB_ID?wait=30" -H "Authorization: Bearer $STAGLIGHT_API_KEY")
  case "$(echo "$JOB" | jq -r .status)" in queued|running) ;; *) break ;; esac
done

# 3. Download the result from outputs[0].download_url.
echo "$JOB" | jq '.outputs[0].download_url // .data'
import os, uuid, requests

BASE = "https://staglight.ai/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['STAGLIGHT_API_KEY']}"}

# 0. Upload your file first and put the id it prints in params.
with open("your-file", "rb") as f:
    print(requests.post(f"{BASE}/uploads", headers=HEADERS, files={"file": f}, timeout=300).json()["id"])

# 1. Create the job. It is charged once and refunded if it fails.
r = requests.post(f"{BASE}/jobs", timeout=60,
                  headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
                  json={
                    "op": "edit.merge",
                    "params": {
                      "clips": ["med_your_upload_id"],
                      "aspect": "9:16"
                    },
                    "max_credits": 10
                  })
r.raise_for_status()
job = r.json()

# 2. Poll until it finishes. Each call waits up to 30 seconds.
while job["status"] in ("queued", "running"):
    job = requests.get(f"{BASE}/jobs/{job['id']}", headers=HEADERS,
                       params={"wait": 30}, timeout=60).json()

# 3. Download the result from outputs[0].download_url.
print(job["outputs"][0]["download_url"] if job["outputs"] else job["data"] or job["error"])
// Node 18 or newer. Save as run.mjs: top-level await needs a module.
const BASE = "https://staglight.ai/api/v1";
const headers = { Authorization: `Bearer ${process.env.STAGLIGHT_API_KEY}` };

// 0. Upload your file first and put the id it prints in params.
// const form = new FormData(); form.append('file', yourFile);
// const { id } = await (await fetch(`${BASE}/uploads`, { method: 'POST', headers, body: form })).json();

// 1. Create the job. It is charged once and refunded if it fails.
let res = await fetch(`${BASE}/jobs`, {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID() },
  body: JSON.stringify({
    "op": "edit.merge",
    "params": {
      "clips": [
        "med_your_upload_id"
      ],
      "aspect": "9:16"
    },
    "max_credits": 10
  }),
});
if (!res.ok) throw new Error((await res.json()).error.message);
let job = await res.json();

// 2. Poll until it finishes. Each call waits up to 30 seconds.
while (job.status === "queued" || job.status === "running") {
  job = await (await fetch(`${BASE}/jobs/${job.id}?wait=30`, { headers })).json();
}

// 3. Download the result from outputs[0].download_url.
console.log(job.outputs[0]?.download_url ?? job.data ?? job.error);
{
  "id": "job_19a2b3c4d5e6f7a8b9c0d1",
  "op": "edit.merge",
  "status": "queued",
  "credits": 10,
  "title": "",
  "params": {
    "clips": [
      "med_your_upload_id"
    ],
    "aspect": "9:16"
  },
  "progress": null,
  "outputs": [],
  "data": null,
  "error": null,
  "run_id": null,
  "source": "api",
  "created_at": "2026-11-06T12:00:00Z",
  "finished_at": null,
  "eta_seconds": 45
}

What it costs

10 cr per run. The settings do not change the price.

The playground shows the exact price for your settings. A job is charged once when it is accepted, and refunded if it fails. The price is checked again with your file before it runs.

Parameters

NameTypeDefaultAllowed
clipsrequiredClips media id[] Video, up to 12
aspectFormat enum 9:16 keep, 9:16, 4:5, 1:1, 16:9
fitFit enum blur blur, pad, crop
musicMusic media id Audio
voiceVoiceover media id Audio
ai_labelAI label boolean false

Send these inside params. Files are media ids from POST /api/v1/uploads. View documentation

More models