Seedance 2.5 Lite uses the model ID picassoia/seedance-2.5-lite. Text and image to video with audio, clips of 5, 10 or 15 seconds and 480p or 720p output.
Calling the API
Send requests to https://api.picassoia.com/v1/models/picassoia/seedance-2.5-lite/predictions with a JSON body whose input matches the parameters below.
Setup
Keep your API key on your server, in an environment variable, and send it in the Authorization header of every request.
export PICASSOIA_API_KEY="pia_sk_…"Request Parameters
promptstringRequired- DefaultNone
- What the output should show. Up to 4000 characters.
imagestring- DefaultNone
- The opening frame, or the image to work from. A PNG, JPEG or WebP image, as a public https URL or as a data URL of up to 5 MB.
last_frame_imagestring- DefaultNone
- The closing frame: the clip ends on it. Requires the image field. A PNG, JPEG or WebP image, as a public https URL or as a data URL of up to 5 MB.
resolutionstring- Default
"480p" - The size of the output. Options: 480p and 720p.
durationnumber- Default
5 - The length of the clip, in seconds. Options: 5, 10 and 15. Up to 15 at 480p. Up to 10 at 720p.
aspect_ratiostring- Default
"match_input_image" / "16:9" - The shape of the output. Where match_input_image is an option, it keeps the proportions of the input image, or of the first one when there are several. Options: match_input_image, 1:1, 16:9, 9:16, 4:3, 3:4, 3:2 and 2:3. If you leave it out: match_input_image when image is sent, 16:9 when it is not.
save_audioboolean- Default
true - Keep the generated audio track.
seedinteger- DefaultNone
- Set it to reproduce a result; leave it out for a random one.
enhance_promptboolean- Default
true - Picasso IA rewrites your prompt for a better result. Your own prompt stays in the input.
Modes
The mode depends on which files, if any, you send with the prompt. Every mode uses the same endpoint.
Example Request
Text to Video
curl -s -X POST https://api.picassoia.com/v1/models/picassoia/seedance-2.5-lite/predictions \
-H "Authorization: Bearer $PICASSOIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"prompt":"a paper boat sailing down a rainy street"}}'const API = 'https://api.picassoia.com/v1'
const headers = {
Authorization: `Bearer ${process.env.PICASSOIA_API_KEY}`,
'Content-Type': 'application/json',
}
const sleep = (s) => new Promise((resolve) => setTimeout(resolve, s * 1000))
const input = {
prompt: "a paper boat sailing down a rainy street"
}
const created = await fetch(`${API}/models/picassoia/seedance-2.5-lite/predictions`, {
method: 'POST',
headers,
body: JSON.stringify({ input }),
})
let prediction = await created.json()
if (!created.ok) throw new Error(`${prediction.code}: ${prediction.detail}`)
while (!['succeeded', 'failed', 'canceled'].includes(prediction.status)) {
await sleep(prediction.eta?.next_poll_in_seconds ?? 2)
prediction = await (await fetch(prediction.urls.get, { headers })).json()
}
if (prediction.status !== 'succeeded') throw new Error(prediction.error ?? prediction.status)
console.log(prediction.output)import os, time, requests
API = "https://api.picassoia.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PICASSOIA_API_KEY']}"}
payload = {"input": {
"prompt": "a paper boat sailing down a rainy street",
}}
response = requests.post(f"{API}/models/picassoia/seedance-2.5-lite/predictions", json=payload, headers=HEADERS)
prediction = response.json()
if not response.ok:
raise RuntimeError(f"{prediction['code']}: {prediction['detail']}")
while prediction["status"] not in ("succeeded", "failed", "canceled"):
time.sleep((prediction.get("eta") or {}).get("next_poll_in_seconds", 2))
prediction = requests.get(prediction["urls"]["get"], headers=HEADERS).json()
if prediction["status"] != "succeeded":
raise RuntimeError(prediction["error"] or prediction["status"])
print(prediction["output"])Image to Video
curl -s -X POST https://api.picassoia.com/v1/models/picassoia/seedance-2.5-lite/predictions \
-H "Authorization: Bearer $PICASSOIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"prompt":"the camera slowly pushes in as she turns and smiles","image":"https://example.com/first-frame.jpg"}}'const API = 'https://api.picassoia.com/v1'
const headers = {
Authorization: `Bearer ${process.env.PICASSOIA_API_KEY}`,
'Content-Type': 'application/json',
}
const sleep = (s) => new Promise((resolve) => setTimeout(resolve, s * 1000))
const input = {
prompt: "the camera slowly pushes in as she turns and smiles",
image: "https://example.com/first-frame.jpg"
}
const created = await fetch(`${API}/models/picassoia/seedance-2.5-lite/predictions`, {
method: 'POST',
headers,
body: JSON.stringify({ input }),
})
let prediction = await created.json()
if (!created.ok) throw new Error(`${prediction.code}: ${prediction.detail}`)
while (!['succeeded', 'failed', 'canceled'].includes(prediction.status)) {
await sleep(prediction.eta?.next_poll_in_seconds ?? 2)
prediction = await (await fetch(prediction.urls.get, { headers })).json()
}
if (prediction.status !== 'succeeded') throw new Error(prediction.error ?? prediction.status)
console.log(prediction.output)import os, time, requests
API = "https://api.picassoia.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PICASSOIA_API_KEY']}"}
payload = {"input": {
"prompt": "the camera slowly pushes in as she turns and smiles",
"image": "https://example.com/first-frame.jpg",
}}
response = requests.post(f"{API}/models/picassoia/seedance-2.5-lite/predictions", json=payload, headers=HEADERS)
prediction = response.json()
if not response.ok:
raise RuntimeError(f"{prediction['code']}: {prediction['detail']}")
while prediction["status"] not in ("succeeded", "failed", "canceled"):
time.sleep((prediction.get("eta") or {}).get("next_poll_in_seconds", 2))
prediction = requests.get(prediction["urls"]["get"], headers=HEADERS).json()
if prediction["status"] != "succeeded":
raise RuntimeError(prediction["error"] or prediction["status"])
print(prediction["output"])First and Last Frame
curl -s -X POST https://api.picassoia.com/v1/models/picassoia/seedance-2.5-lite/predictions \
-H "Authorization: Bearer $PICASSOIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"prompt":"a smooth transition from day to night over the city","image":"https://example.com/first-frame.jpg","last_frame_image":"https://example.com/last-frame.jpg"}}'const API = 'https://api.picassoia.com/v1'
const headers = {
Authorization: `Bearer ${process.env.PICASSOIA_API_KEY}`,
'Content-Type': 'application/json',
}
const sleep = (s) => new Promise((resolve) => setTimeout(resolve, s * 1000))
const input = {
prompt: "a smooth transition from day to night over the city",
image: "https://example.com/first-frame.jpg",
last_frame_image: "https://example.com/last-frame.jpg"
}
const created = await fetch(`${API}/models/picassoia/seedance-2.5-lite/predictions`, {
method: 'POST',
headers,
body: JSON.stringify({ input }),
})
let prediction = await created.json()
if (!created.ok) throw new Error(`${prediction.code}: ${prediction.detail}`)
while (!['succeeded', 'failed', 'canceled'].includes(prediction.status)) {
await sleep(prediction.eta?.next_poll_in_seconds ?? 2)
prediction = await (await fetch(prediction.urls.get, { headers })).json()
}
if (prediction.status !== 'succeeded') throw new Error(prediction.error ?? prediction.status)
console.log(prediction.output)import os, time, requests
API = "https://api.picassoia.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PICASSOIA_API_KEY']}"}
payload = {"input": {
"prompt": "a smooth transition from day to night over the city",
"image": "https://example.com/first-frame.jpg",
"last_frame_image": "https://example.com/last-frame.jpg",
}}
response = requests.post(f"{API}/models/picassoia/seedance-2.5-lite/predictions", json=payload, headers=HEADERS)
prediction = response.json()
if not response.ok:
raise RuntimeError(f"{prediction['code']}: {prediction['detail']}")
while prediction["status"] not in ("succeeded", "failed", "canceled"):
time.sleep((prediction.get("eta") or {}).get("next_poll_in_seconds", 2))
prediction = requests.get(prediction["urls"]["get"], headers=HEADERS).json()
if prediction["status"] != "succeeded":
raise RuntimeError(prediction["error"] or prediction["status"])
print(prediction["output"])Authentication
Every request needs an API key in the Authorization header, as a Bearer token. Create keys in your account; the full key is shown once.
Authorization: Bearer $PICASSOIA_API_KEYQueue and Polling
Every prediction takes three steps: create it, poll it until it finishes, then read the result.
Submit
The API answers 201, usually within seconds, with the prediction in the starting state, an estimate in eta and the URL to poll in urls.get. If the prediction fails right away, for example when the safety filter refuses the input, the answer is still 201, with the prediction in the failed state and its error.
curl -s -X POST https://api.picassoia.com/v1/models/picassoia/seedance-2.5-lite/predictions \
-H "Authorization: Bearer $PICASSOIA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"input":{"prompt":"a paper boat sailing down a rainy street"}}'const API = 'https://api.picassoia.com/v1'
const headers = {
Authorization: `Bearer ${process.env.PICASSOIA_API_KEY}`,
'Content-Type': 'application/json',
}
const input = {
prompt: "a paper boat sailing down a rainy street"
}
const created = await fetch(`${API}/models/picassoia/seedance-2.5-lite/predictions`, {
method: 'POST',
headers,
body: JSON.stringify({ input }),
})
let prediction = await created.json()
if (!created.ok) throw new Error(`${prediction.code}: ${prediction.detail}`)
console.log(prediction.id, prediction.status) // api_…, startingimport os, requests
API = "https://api.picassoia.com/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PICASSOIA_API_KEY']}"}
payload = {"input": {
"prompt": "a paper boat sailing down a rainy street",
}}
response = requests.post(f"{API}/models/picassoia/seedance-2.5-lite/predictions", json=payload, headers=HEADERS)
prediction = response.json()
if not response.ok:
raise RuntimeError(f"{prediction['code']}: {prediction['detail']}")
print(prediction["id"], prediction["status"]) # api_…, starting{
"id": "api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60",
"model": "picassoia/seedance-2.5-lite",
"input": {
"prompt": "a paper boat sailing down a rainy street",
"resolution": "480p",
"duration": 5,
"aspect_ratio": "16:9",
"save_audio": true,
"enhance_prompt": true
},
"output": null,
"error": null,
"status": "starting",
"created_at": "2026-10-01T09:30:00.000Z",
"started_at": null,
"completed_at": null,
"metrics": {
"predict_time": null
},
"urls": {
"get": "https://api.picassoia.com/v1/predictions/api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60",
"cancel": "https://api.picassoia.com/v1/predictions/api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60/cancel"
},
"eta": {
"seconds": 60,
"next_poll_in_seconds": 30
}
}Poll
Poll urls.get again after eta.next_poll_in_seconds: at half the estimate, when the estimate is reached, then every 2 seconds.
# Repeat after eta.next_poll_in_seconds until status is
# succeeded, failed or canceled.
curl -s https://api.picassoia.com/v1/predictions/api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60 \
-H "Authorization: Bearer $PICASSOIA_API_KEY"const sleep = (s) => new Promise((resolve) => setTimeout(resolve, s * 1000))
while (!['succeeded', 'failed', 'canceled'].includes(prediction.status)) {
await sleep(prediction.eta?.next_poll_in_seconds ?? 2)
prediction = await (await fetch(prediction.urls.get, { headers })).json()
}import time
while prediction["status"] not in ("succeeded", "failed", "canceled"):
time.sleep((prediction.get("eta") or {}).get("next_poll_in_seconds", 2))
prediction = requests.get(prediction["urls"]["get"], headers=HEADERS).json(){
"id": "api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60",
"status": "processing",
"output": null,
"eta": {
"seconds": 30,
"next_poll_in_seconds": 30
}
}Result
When status is succeeded, output holds the result. A failed prediction carries its reason in error, and a canceled one was stopped before it finished. All three statuses are final.
# The last poll holds the result: "output" when "status" is succeeded,
# "error" when it is failed. With jq, just those three fields:
curl -s https://api.picassoia.com/v1/predictions/api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60 \
-H "Authorization: Bearer $PICASSOIA_API_KEY" | jq '.status, .output, .error'if (prediction.status !== 'succeeded') throw new Error(prediction.error ?? prediction.status)
console.log(prediction.output)if prediction["status"] != "succeeded":
raise RuntimeError(prediction["error"] or prediction["status"])
print(prediction["output"]){
"id": "api_3f9c2b7e8d1a4c6f9e0b1a2c3d4e5f60",
"status": "succeeded",
"output": "https://…/output.mp4",
"error": null,
"completed_at": "2026-10-01T09:30:54.000Z",
"metrics": {
"predict_time": 52.8
},
"eta": null
}Cancel
POST urls.cancel stops a prediction that is still queued (any model) or an image that is still generating; a video already generating answers 409 not_cancelable.
The IDs, times and URLs in these responses are examples: yours will have their own.
Output
When the prediction succeeds, output is the URL of an MP4 video.
Real Outputs
Errors and Limits
Errors are JSON problem details with a stable code, and a 422 names every field at fault.
{
"title": "Input validation failed",
"status": 422,
"code": "invalid_input",
"detail": "input.duration: At 720p the longest clip is 10 seconds.",
"invalid_fields": [
{
"type": "invalid_value",
"field": "input.duration",
"description": "At 720p the longest clip is 10 seconds."
}
]
}Limits
- 5 predictions queued or running at once per account
- Request body up to 10 MB; images as data URLs up to 5 MB each
- Prompt up to 4000 characters
- Unknown fields are refused with 422 invalid_input
Pricing
$0 per request with an active Infinite plan: API predictions use no credits, whatever the settings.
Other providers charge from ~$0.2205/s for a comparable model (as of October 1, 2026).
API PricingJSON Schema
The same schema the API serves at GET /v1/models/picassoia/seedance-2.5-lite.
{
"input_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"prompt": {
"type": "string",
"minLength": 1,
"maxLength": 4000,
"description": "What happens in the video."
},
"image": {
"type": "string",
"description": "Opening frame (image-to-video): an https URL or a data URL."
},
"last_frame_image": {
"type": "string",
"description": "Closing frame: an https URL or a data URL. Needs image as well."
},
"resolution": {
"default": "480p",
"description": "480p (up to 15 s) or 720p (up to 10 s).",
"type": "string",
"enum": [
"480p",
"720p"
]
},
"duration": {
"default": 5,
"description": "Length in seconds: 5, 10 or 15.",
"type": "number",
"enum": [
5,
10,
15
]
},
"aspect_ratio": {
"description": "Default: match_input_image when there is an image, 16:9 without one.",
"type": "string",
"enum": [
"match_input_image",
"1:1",
"16:9",
"9:16",
"4:3",
"3:4",
"3:2",
"2:3"
]
},
"save_audio": {
"default": true,
"description": "Keep the generated audio track.",
"type": "boolean"
},
"seed": {
"description": "Random seed. Set it to reproduce a result.",
"type": "integer",
"minimum": -9007199254740991,
"maximum": 9007199254740991
},
"enhance_prompt": {
"default": true,
"description": "Let PicassoIA rewrite the prompt for a better video before generating it.",
"type": "boolean"
}
},
"required": [
"prompt"
],
"additionalProperties": false
},
"output_schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"format": "uri",
"description": "URL of the generated video (MP4)."
}
}