Image to video
Animate an image you uploaded, guided by a prompt.
Give PierNode an image you have uploaded and an instruction, and get back a video that animates it — "slow pan across the scene", "the water begins to ripple", "camera pulls back to reveal the room".
Same vocabulary as Text to video: the same resolutions, aspect ratios and duration range, because it is the same model with your image supplied as the opening frame.
Before you start
You need an upload in the READY state. See Uploading an image:
POST /api/v1/uploads → { id, uploadUrl }
PUT <uploadUrl> → your image bytes
POST /api/v1/uploads/{id}/complete → { status: "READY" }Keep that id. It is the assetId below, and one upload can feed as many
generations as you like — animating an image does not consume it.
POST /api/v1/videos/transformations
curl -X POST https://app.piernode.com/api/v1/videos/transformations \
-H "Authorization: Bearer $PIERNODE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"assetId": "c8f2a1d4e5b64c9a8f3d2e1b0a9c8d7e",
"prompt": "slow pan across the scene",
"resolution": "720p",
"durationSeconds": 5
}'Request
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
assetId | string | yes | — | A READY upload of yours. |
prompt | string | yes | — | 1–2000 characters. Describes the motion. |
resolution | string | no | 720p | 480p, 512p, 720p, 1080p. |
aspectRatio | string | no | the input's shape | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. |
durationSeconds | int | no | 5 | 4–15. |
By default the output keeps roughly the shape of the image you uploaded, so a
landscape photo animates as landscape rather than being cropped or stretched
into a 16:9 box. Set aspectRatio when you want to change it.
Request bodies are limited to 64 KB. Any field not listed above is ignored — in
particular there is no way to pass an image URL, an object key or a bucket. The
input is always one of your own uploads, named by assetId.
Response
{
"id": "fu0825tesv0laouebtjx0x5w",
"status": "QUEUED",
"createdAt": "2026-01-01T12:00:00.000Z"
}Poll GET /api/v1/tasks/\{taskId\} until status is SUCCEEDED or FAILED.
Result
{
"status": "SUCCEEDED",
"output": {
"videos": [{ "url": "https://...", "contentType": "video/mp4", "sizeBytes": 8388608 }]
}
}Result links are valid for one hour. Re-poll the task for a fresh one.
The result is a generation output, not a new upload — it does not get an
assetId. Your input upload is unchanged and still usable.
Errors
| Status | Meaning |
|---|---|
400 | No usable upload for that assetId — it is not yours, does not exist, or is not READY. |
402 | Your balance is too low to start this generation. |
429 | Too many generation requests. The limit is 60 per minute per account. |
503 | That resolution is not currently available. |
Nothing is reserved unless the task is accepted, and a failed generation is refunded in full.
Pricing
Charged per second, at a rate that depends on the resolution — the same shape as text to video, but priced separately. Current rates are shown on your dashboard.
Cancelling
POST /api/v1/tasks/\{taskId\}/cancel refunds a task that has not started yet.
Once processing has begun it returns 409, because the work upstream cannot be
recalled.