Text to video api

A prompt alone is a text clip. An image animates that photo for one clip. Poll /api/videos/{id}/ with the same key until the clip is READY.

$1 for a 5-second 540x960 clip (12 credits). The ultra tier is 720x1280.

Auth

Create a key at /users/api-keys/. The plaintext is shown once and starts with sk_live_.

HeaderAuthorization: Bearer then the key
Also acceptedX-API-Key with the same key
Missing key401 {"detail": "Authentication credentials were not provided."} on a read. Generate allows an account-less caller only while machine payments are on, and then answers 402.
Unknown or inactive key401 {"detail": "Invalid API key"}

POST /api/videos/generate/

JSON body. A prompt creates a text clip. Set image to animate a photo. The response is 201 as soon as the job is queued.

promptRequired string, at most 1000 characters.
durationInteger. Default 5, minimum 5, maximum 60. An image replaces it with 5. When the account has an API quota, a non-staff key cannot ask for more than that quota's max_video_duration. The message is Duration cannot exceed {max_video_duration} seconds for your subscription plan.
resolutionTier key. Accepted values: 540x960, 720x1280. Default 540x960. An image replaces it with 540x960. Any other tier is rejected.
imageOptional. An https URL or a photo file as base64. http is rejected with Image must be an https URL or a photo file. A file that is not a photo is rejected with That file is not a photo. A stored photo is at most 2048 pixels on the long edge and 8000000 bytes. An https URL is fetched later, up to 41943040 bytes.
negative_promptOptional string, at most 500 characters. Blank and null are accepted.
seedOptional integer. Null is accepted.
curl -X POST https://sisif.ai/api/videos/generate/ \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"prompt": "A lighthouse at dusk", "duration": 5, "resolution": "540x960"}'

201 body

idInteger video id.
statusThe row's status after the job is queued, which is PROCESSING.
promptThe prompt that was stored.
durationSeconds stored. An image request stores 5.
resolutionTier key stored. An image request stores 540x960.
estimated_completionA timestamp 5 minutes after the response is built.
credits_usedCredits calculated for that duration and tier before the job starts.
created_atWhen the row was created.
api_keyPresent only when a payment with no account minted a key. Shown once. That key is how the caller polls.

GET /api/videos/{id}/

Poll with the same Bearer key. The clip must belong to that key's account. Repeat the GET until status is READY, ERROR, REFUNDED.

Statuses: PENDING, QUEUED, RETRYING, PROCESSING, READY, ERROR, REFUNDED. Still running: PENDING, QUEUED, RETRYING, PROCESSING.

idInteger.
promptString.
statusOne of the statuses above.
video_urlFile URL. Empty until the file is stored.
poster_urlPoster URL. Empty when there is no poster.
durationSeconds.
resolutionTier key, not a measured pixel size.
output_widthStored file width, or null before it is known.
output_heightStored file height, or null before it is known.
featuredBoolean. New API clips are not featured.
created_atTimestamp.
updated_atTimestamp.

GET /api/videos/{id}/status/

The same account scope. Always returns id, status, progress, created_at, and updated_at. video_url is included when status is READY and the file URL is set. poster_url is included when a poster is set. error_message is included when status is ERROR, using the stored message or Generation failed.

PENDINGprogress 10
PROCESSINGprogress 50
READYprogress 100
ERRORprogress 0
Any other statusprogress 0

Watch

The watch page is /app/watch/{id}/. It answers only when status is READY and the clip is featured, public, or the viewer is signed in as the owner. An API clip starts private and unfeatured, so the owner opens that page while signed in. The file itself is video_url on the detail response.

Errors

400{"error": "validation_error", "message": "Invalid request data", "details": {}} and details is the field errors.
401{"detail": "..."}. Invalid API key, or Rate limit exceeded (per minute), Rate limit exceeded (per hour), or Rate limit exceeded (per day).
402insufficient_credits when the account is short: message Insufficient credits. Need {cost}, have {balance}, details required_credits and available_credits. payment_required when there is no account: message This clip costs {cost} credits. Pay the challenge in WWW-Authenticate., details required_credits and usd_amount. payment_failed when a credential is refused. A replayed payment says payment already redeemed.
404{"detail": "Not found."} for a missing id or another account's clip.
429An unkeyed generate call past the anonymous limit. The detail is Request was throttled. Expected available in {wait} second. when the wait is 1, and Request was throttled. Expected available in {wait} seconds. otherwise. The response carries Retry-After. A keyed caller who is over the key's own limit gets 401, not 429.
502{"error": "generation_failed", "message": "Video generation could not be started. Please try again."} Credits are not taken when the job never queues. A later failure returns the credits.

Limits and price

$1 buys 12 credits: 5 seconds at 540x960. Credits for a text clip are the duration times the tier coefficient, with the fraction dropped. An image is priced as that same clip, because duration and resolution are replaced.

540x9602.5 credits per second
720x12806.0 credits per second
Per key10 per minute, 100 per hour, 1000 per day. Those are the defaults on a new key.
No key30/hour on generate, per address.
Prompt1000 characters. Negative prompt 500.
Duration5 to 60 seconds, unless a quota sets a lower maximum.