Developers

Video API

One POST turns a sentence into a short film with native audio. Billed by the second of finished video — a flat 40 credits a second, and nothing else.

Three steps

1

Get a key

Sign in, open your account page, create an API key. It is shown once — save it. The same key works for the Director API.

2

Top up

Credits are prepaid on the same page. US$1 buys 1,000 credits, valid for 12 months.

3

Call it

POST a prompt, get a job_id back immediately, poll until it is done. Rendering takes minutes — write it as a job, not as a request.

Go to my account Try it in the browser first

What it costs

A flat 40 credits per second of finished video, at any hour. No per-request fee, no resolution tiers, no charge for a failed render. The day and night rates on the pricing page are for the website only; the API does not use them, and it does not use free seconds.

LengthCreditsRender time
4 s160about 3 min
8 s320about 8 min
10 s400about 10 min
15 s600about 17 min

All three modes cost the same, and so does every aspect ratio. Credits are held when you submit and become the charge on success. A failed or cancelled job is refunded in full, same minute. Render times are estimates, not promises — the number that matters is deliver_by in the response.

Three ways to make a clip

Same model, same price, same endpoint — mode picks which one you get.

modeWhat it doesWhat you send
textWords in, film out. The default; omit mode and you get this.prompt
animateA photo starts moving. Give a first frame; add a last frame and it moves between the two.first_frame, optional last_frame
castPut a specific person, object, look or voice in the shot. Point at them in the prompt as <Picture 1>, <Audio 1>.ref_images and/or ref_audios

GET /v1/models tells you which modes are open right now. We turn them on one at a time; a mode that is not open returns mode_unavailable rather than pretending.

Lip sync

Give cast mode a reference audio and the person in your clip speaks it — mouth movement follows the recording.

Portrait, landscape and square

Pass ratio. Every shape costs the same and takes the same time, so pick by where the video is going, not by budget.

ratioWhat it is for
16:9Landscape. The default — omit ratio and you get this.
9:16Vertical, for phones — TikTok, Reels, Shorts.
1:1Square, for feeds.

How long it takes, honestly

Submit a job

curl -X POST https://spaceskills.shop/v1/videos \
  -H "Authorization: Bearer $SPACESKILLS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-clip-0001" \
  -d '{
    "prompt": "A red paper boat drifting on a calm pond at sunrise, soft golden light, gentle ripples on the water, slow push-in, cinematic",
    "duration_sec": 5
  }'
HTTP/1.1 202 Accepted
{
  "job_id": "vid_8Qk2ZrX1c0Nn",
  "status": "queued",
  "model": "h3/768p",
  "duration_sec": 5,
  "credits_held": 200,
  "balance": 9800,
  "queue_position": 1,
  "est_render_sec": 259,
  "deliver_by": "2026-09-09T14:31:07.000Z",
  "poll": "/v1/videos/vid_8Qk2ZrX1c0Nn"
}

Returns 202 with a job_id and the credits held. Send an Idempotency-Key and a retried POST returns the same job instead of charging twice.

curl https://spaceskills.shop/v1/videos/vid_8Qk2ZrX1c0Nn \
  -H "Authorization: Bearer $SPACESKILLS_API_KEY"
{
  "job_id": "vid_8Qk2ZrX1c0Nn",
  "status": "succeeded",
  "duration_sec": 5,
  "seed": 774512900183,
  "credits_held": 0,
  "credits_charged": 200,
  "output": {
    "url": "https://media.spaceskills.shop/relay/vid_8Qk2ZrX1c0Nn.mp4",
    "stored": true
  },
  "error": null,
  "created_at": "2026-09-09T14:21:44.910Z",
  "updated_at": "2026-09-09T14:25:12.338Z"
}

status is one of queued, running, succeeded, failed, cancelled. On succeeded, output.url is the finished MP4 with audio muxed in.

Sending images and audio

Same shape as the Director API: each file is inline base64 or an https URL we fetch.

# cast: put a specific face, object or look in the shot
curl -X POST https://spaceskills.shop/v1/videos \
  -H "Authorization: Bearer $SPACESKILLS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "cast",
    "prompt": "The woman from <Picture 1> walks slowly through a rainy neon street at night, reflections on wet asphalt, rain and distant traffic, slow tracking shot",
    "duration_sec": 6,
    "ref_images": [
      { "name": "her.jpg", "url": "https://example.com/her.jpg" }
    ]
  }'

# animate: start from a photo
curl -X POST https://spaceskills.shop/v1/videos \
  -H "Authorization: Bearer $SPACESKILLS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "animate",
    "prompt": "The lake ripples as the sun sinks lower, drifting clouds, distant birdsong, slow push-in",
    "duration_sec": 5,
    "first_frame": { "name": "lake.jpg", "url": "https://example.com/lake.jpg" }
  }'

Endpoints

EndpointWhat it does
GET /v1/modelsCatalogue: length range, price per second, current queue depth. Free, no key needed.
POST /v1/videosSubmit a prompt. Holds credits, returns job_id.
GET /v1/videos/{id}Status, and the file once it is ready.
GET /v1/videosYour last 30 jobs and your balance. Useful for reconciliation.
POST /v1/videos/{id}/cancelCancel while still queued. Full refund. Once it is running the GPU time is already spent, so it cannot be cancelled.

Request fields

FieldTypeNotes
promptstringWhat the shot should show. 8 to 20000 characters. Subject, motion, setting, light, camera — in that order works well.
duration_secinteger4 to 15. This is the pricing basis. Defaults to 5.
modestringtext, animate or cast. Defaults to text.
first_framefileanimate only, required. The frame the clip starts on.
last_framefileanimate only, optional. The frame it ends on.
ref_imagesfile[]cast only, up to 4. Refer to them in the prompt as <Picture 1> onwards, in the order you sent them.
ref_audiosfile[]cast only, up to 3. The voice the person speaks — this is what drives lip sync. Refer to them as <Audio 1>.
ratiostring16:9 (default), 9:16 or 1:1. Same price, same render time. GET /v1/models is authoritative — the list can change.
modelstringDefaults to h3/768p, currently the only active model.
seedintegerOptional. Same seed, prompt and images reproduce the same clip. Omit it and one is drawn and echoed back on the job.

Headers: Authorization: Bearer sk_live_… and, recommended, Idempotency-Key: <any string you generate>. A key is remembered per account, so a network retry can never buy the same clip twice.

What comes back

The same job object from submit, poll and list — only the fields that are known yet are filled in.

Writing a prompt that works

The model reads plain prose, English or Chinese. It rewards specificity and punishes lists of adjectives.

Browse the prompt library

When things go wrong

CodeMeans
unauthorizedMissing or wrong key. Use Authorization: Bearer sk_live_…
insufficient_creditsBalance below the price. The response tells you both numbers.
bad_paramsNo prompt, prompt too long, or duration_sec outside 4–15.
unknown_modelNo such active model. Check GET /v1/models.
mode_unavailableThat mode is not open yet. The response lists the ones that are.
bad_materialAn image was too large, not a real JPEG/PNG/WebP, unreachable, or not https. The message says which slot.
payload_too_largeThe request body is over 24 MB. Send images as https URLs instead of inline base64.
model_unavailableNo render backend right now — usually a machine swap. Retry in a few minutes; nothing was charged.
capacity_deadline_infeasibleThe queue is deeper than six hours. Retry later; nothing was charged.
idempotency_conflictThat Idempotency-Key is in use by a different request body.
not_cancellableThe job is already running or finished.
rate_limitedToo many requests. Retry-After says how long to wait.

Limits

Want the director to plan and render the whole film for you? See the Director Agent

Questions, or something behaving oddly? Tell us