Skip to main content

Continue a clip with Seedance 2.0 Mini: the last frame of your video opens a new 4 to 15 second segment with sound, and you get back one file with the original and the continuation joined, at 480p or 720p.

From $0.025/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
# 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": "bytedance/seedance-2.0-mini/video-extend",
  "input": {
    "bitrate_mode": "standard",
    "duration_seconds": 5,
    "enable_web_search": false,
    "generate_audio": true,
    "resolution": "720p",
    "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_urlstringRequired

The clip to continue: MP4, MOV or WebM, up to 60 seconds. Its final frame becomes the opening frame of the new segment, so cut it on a clean, sharp frame. The source is not billed.

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

Adds the model’s own visible "AI generated" watermark to the new segment. Off by default; switch it on when the place you publish requires AI-made footage to be labelled. No effect on price.

Default
false
bitrate_modestringOptional

Encoding bitrate of the new segment as the model delivers it: `standard` (default) or `high`. High keeps fine texture and fast motion crisper and makes the segment file much larger; the joined file is encoded again by the platform. No effect on price.

Default
"standard"
Allowed values
"standard""high"
seedintegerOptional

Integer from 0 to 2147483647; omit it and each run draws its own. Hold it fixed to compare one changed field at a time; it is a comparison tool, not a promise of frame-identical repeats.

Default
Not specified
Constraints
minimum:0
maximum:2147483647
enable_web_searchbooleanOptionalAffects price

Off by default. Switched on, the model may search the web for information related to your prompt before it renders the new segment. Requests with it on are billed at the web-search rate, which is higher than the standard rate; the estimate shown before you submit already reflects it.

Default
false
generate_audiobooleanOptional

On by default, so the new segment comes with generated sound; switching it off does not lower the price in this tier. Your source keeps its own sound either way; when one side is silent, the joined file is padded with silence.

Default
true
duration_secondsintegerOptionalAffects price

Length of the new segment in whole seconds: 4 to 15, or -1 to let the model choose, in which case 15 seconds are held up front and the charge settles on the length delivered. Defaults to 5. Your source is added on top and is not billed.

Default
5
Allowed values
-1456789101112131415
resolutionstringOptionalAffects price

Size of the new segment: 480p or 720p, default 720p. Match your source: it only sets the quality of the new segment, and a lower setting makes the new part look softer than the original. The joined file keeps your clip’s framing with no black bars; to line the seam up, the picture may be trimmed or adjusted by a few percent at the edges. If the model returns a noticeably different shape, the new segment is scaled to fill your frame and centered, cropping what spills over. It sets the price.

Default
"720p"
Allowed values
"480p""720p"
last_image_urlstringOptional

Optional target end frame: the new segment lands on this picture instead of ending wherever the model chooses. Useful for a transition or a loop back to a known frame. Give it the same proportions as the last frame of your clip, or it is cropped to match. Each side must be between 300 and 6000 pixels; a smaller picture is rejected by the input check before you are charged.

Default
Not specified
Constraints
contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]
promptstringOptional

Optional. What happens next: the action that follows, the camera move and the sound. Left out, the model decides the motion from the last frame. The opening frame already fixes the subject and the set, so spend any words on motion.

Default
Not specified
Constraints
minLength:1

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": "bytedance/seedance-2.0-mini/video-extend",
    "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 Seedance 2.0 Mini · Video Extend 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