Skip to main content

minimax/h3-edit/video-edit

MiniMax H3 video edit rewrites the weather, light, style or setting of a clip you send, while your footage keeps driving who is in it, the composition and the motion. Edits run 3 to 15 seconds at 480p, 540p or 768p, with new sound by default.

From $0.03/s

Workbench

Send a request

Quickstart

Examples use the selected endpoint’s public parameter definitions. Replace the API key and example media, then send the request from your server.

SDKs & integrations
POSThttps://api.spicyapi.ai/api/v1/jobs/createTask

API authentication

Keep the API key in the server environment variable SPICY_API_KEY. Use Bearer authentication and Content-Type: application/json for JSON requests.

Authorization: Bearer $SPICY_API_KEY
Sample outputUse this example
# Generate the idempotency key once; reuse it when retrying after a lost response.
export SPICY_IDEMPOTENCY_KEY="${SPICY_IDEMPOTENCY_KEY:-$(uuidgen)}"
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
  -d '{
  "model": "minimax/h3-edit/video-edit",
  "input": {
    "duration_seconds": 5,
    "prompt": "A slow aerial shot drifting over a misty pine forest at sunrise",
    "resolution": "768p",
    "video_url": "https://example.com/reference.mp4"
  }
}'

# Copy data.taskId from the response into TASK_ID, then poll the status.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.spicyapi.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Generated from this model’s input schema — the same one the API validates every request against.

Input parameters

Place these fields inside the request body’s input object. Names and types match the API. Do not assume a default when none is specified.

video_urlstringRequiredAffects price

The clip to edit, as an MP4. Up to 15 seconds long; a longer clip is refused before anything is charged, so trim it first. Use footage you are allowed to edit.

Default
Not specified
Constraints
format:"uri"
contentMediaType:["video/mp4","video/webm","video/quicktime"]
promptstringRequired

Write the edit as a change: what to alter, then what to keep. For example, turn the afternoon into a stormy dusk and keep her face and movement. Refer to reference images as <Picture 1>, <Picture 2> and reference audio as <Audio 1>, <Audio 2>.

Default
Not specified
Constraints
minLength:3
maxLength:5000
seedintegerOptional

Optional integer. Send a fixed value while you change one thing at a time, so takes are easier to compare.

Default
Not specified
Constraints
minimum:0
maximum:2147483647
generate_audiobooleanOptional

On by default, which gives the edit a new soundtrack. Turn it off to keep the source clip's own audio track. Sound does not change the price.

Default
true
duration_secondsintegerOptionalAffects price

Length of the edited clip: 3 to 15 seconds, default 5. Set it to your source clip's length to edit the whole clip.

Default
5
Constraints
minimum:3
maximum:15
resolutionstringOptionalAffects price

480p, 540p or 768p, default 768p, which is H3's own canvas. Lower tiers cost less per second and finish sooner, but the same prompt can look different: in our storm test the 480p trial showed stronger rain than 768p.

Default
"768p"
Allowed values
"480p""540p""768p"
aspect_ratiostringOptional

Optional. Leave it out and the edit keeps the shape of the source clip. Otherwise 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 or 9:21.

Default
Not specified
Allowed values
"16:9""9:16""1:1""4:3""3:4""21:9""9:21"
reference_audio_urlsarray<string>OptionalAffects price

Up to three audio clips that guide the sound. They are called <Audio 1> to <Audio 3> in the prompt, by their position in the list. Each one adds a small charge.

Default
Not specified
Constraints
minItems:1
maxItems:3
reference_image_urlsarray<string>OptionalAffects price

Up to nine images that guide identity or style. They are called <Picture 1> to <Picture 9> in the prompt, by their position in the list. Each one adds a small charge.

Default
Not specified
Constraints
minItems:1
maxItems:9

Track the task

HTTP 202 means the task was accepted, not completed. Save the returned taskId and query that task. Do not create another task while waiting for its result.

Accepted response
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3

{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_create",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued",
    "estimatedCost": "0.750000"
  }
}

The accepted response includes the estimate so your app can show the same amount in task history and billing.

Read the job
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
  --data-urlencode "taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Start polling at about 2 seconds and gradually increase the interval. Stop at a terminal state. After a connection failure, query the original taskId. Retry creation only with the original idempotency key and body.

Or let the callback find you
import { verifyWebhook } from "@spicyapi/sdk";

// express.raw keeps the bytes we signed; express.json never matches.
app.post("/hooks/spicy", express.raw({ type: "application/json" }), (req, res) => {
  const { payload } = verifyWebhook({
    rawBody: req.body,
    timestamp: req.header("X-Webhook-Timestamp"),
    signature: req.header("X-Webhook-Signature"),
    payloadVersion: Number(req.header("X-Webhook-Payload-Version")),
    secret: process.env.SPICY_WEBHOOK_SECRET,
  });
  res.status(200).end();
  void handleFinishedTask(payload);
});

Pass callBackUrl when you create the task and the finished record is POSTed to you — no polling loop at all. Every delivery carries X-Webhook-Timestamp, X-Webhook-Signature and X-Webhook-Payload-Version. The signature is a base64 HMAC-SHA256 over taskId.timestamp.sha256(body), so it must be checked against the raw bytes: parsing the JSON and re-serialising it changes them and the check will fail. Failed deliveries are retried, so the same taskId can arrive twice — make the handler idempotent. Answer 2xx first and do the work afterwards; a slow handler is treated as a failed delivery.

Read the result

Consume output only when state is succeeded. On failure, use errorCode, errorMessage and request_id to investigate. Example costs and states do not represent an actual bill.

Completed response example
{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_record",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "model": "minimax/h3-edit/video-edit",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "key": "tasks/2026/08/28/job_01k3m8x9q2z4v7n5p6r8s0t1w3/3f7a1c9e5b2d48f0a6c1e3d5b7f9a1c3.mp4",
          "mime": "video/mp4",
          "url": "https://example.r2.cloudflarestorage.com/results/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.mp4?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
          "expiresAt": "2026-08-28T12:20:08.000Z"
        }
      ]
    },
    "cost": "0.750000",
    "settled": true,
    "createdAt": "2026-08-28T12:00:00Z",
    "completedAt": "2026-08-28T12:00:30Z"
  }
}

For each available asset, open or download assets[].url directly without an API Authorization header. The signed URL expires at expiresAt; poll the task again to refresh it while the asset remains within its retention period. A pending or unavailable asset has no URL. Treat signed URLs as private.

SDKs & integrations

Use SpicyAPI in your app, terminal, AI assistant or visual workflow. Choose a setup guide below.

Use it in ComfyUI

Install the SpicyAPI nodes from ComfyUI Manager or with the command below, then search for MiniMax H3 Edit · Video Edit on the canvas. The node has the same options as this page and shows its price before it runs.

cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapi