PierNode
Videos

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

FieldTypeRequiredDefaultNotes
assetIdstringyesA READY upload of yours.
promptstringyes1–2000 characters. Describes the motion.
resolutionstringno720p480p, 512p, 720p, 1080p.
aspectRatiostringnothe input's shape16:9, 9:16, 1:1, 4:3, 3:4, 21:9.
durationSecondsintno54–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

StatusMeaning
400No usable upload for that assetId — it is not yours, does not exist, or is not READY.
402Your balance is too low to start this generation.
429Too many generation requests. The limit is 60 per minute per account.
503That 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.

On this page