Ziztu API

The Ziztu API is a REST API at https://getziztu.com/api/v1. Send an API key, create a project, let the Director plan it and make frames and clips, with a max_credits cap on every paid call.

Updated

Auth and base URL

Base URL: https://getziztu.com/api/v1. The OpenAPI 3.1 spec is at https://getziztu.com/api/v1/openapi.json.

  1. Open the Studio at getziztu.com/app and sign in. Open Settings, then API keys.
  2. Name the key (for example "Claude Code") and pick its scopes: read to look around, generate to plan and make things, export to download films.
  3. Copy the key. It starts with sk_sakuga_ and is shown once.

Send the key on every request, in either header:

Headers
Authorization: Bearer sk_sakuga_your_key
X-API-Key: sk_sakuga_your_key

Use one of the two. A key acts as your account and spends its credits.

Scopes: read for every GET, generate for every change including paid generation, export for renders and downloads. A key can hold any of them. You can have up to 20 active keys.

Spend safety

Every call that costs credits needs max_credits. The call is refused if the real price is higher, and nothing is started. To see the price first, add dry_run: true:

POST /api/v1/projects/:pid/generate/frames
{
  "max_credits": 200,
  "dry_run": true
}

Returns { "quote": ... } and starts nothing. Drop dry_run to run it. The same body works on animate and music.

  • max_credits is required on every call that costs credits: first frames, clips, music and Studio app runs. If the price is higher, the call is refused before anything starts.
  • Above 500 credits, add confirm: true. A bigger spend needs a second, explicit yes.
  • Ask the price first. dry_run: true or the quote tool returns the exact credits and starts nothing. The quote also lists any shot that is blocked, and why.
  • Retries are safe with an Idempotency-Key header: the same key and body returns the first answer instead of running twice.
  • Scope the key. A key without generate cannot start paid work. Make a read key for an agent that should only look.
  • Revoke it any time under Settings, API keys. It stops working at once.

A full session with curl

From a new project to an exported film. Replace PID, MID and JID with the ids in the replies.

From a new project to an export
BASE=https://getziztu.com/api/v1
AUTH="Authorization: Bearer $ZIZTU_TOKEN"
JSON='Content-Type: application/json'

# 1. Check the key and the balance
curl -s $BASE/credits -H "$AUTH"

# 2. Create a project (9:16 for a vertical micro drama)
curl -sX POST $BASE/projects -H "$AUTH" -H "$JSON" \
  -d '{"name":"Dough letter","aspect":"9:16"}'
PID=...   # the id in the reply

# 3. Ask the Director to plan it. The reply has an id and proposed actions
curl -sX POST $BASE/projects/$PID/director/chat -H "$AUTH" -H "$JSON" \
  -d '{"message":"Plan a 60 second micro drama about a baker who finds a love letter in the dough"}'
MID=...   # message.id in the reply

# 4. Apply the free actions: the cast, the places and the shots
curl -sX POST $BASE/projects/$PID/director/messages/$MID/apply-all -H "$AUTH"

# 5. Price the first frames. Nothing is spent
curl -sX POST $BASE/projects/$PID/generate/frames -H "$AUTH" -H "$JSON" \
  -d '{"max_credits":999,"dry_run":true}'

# 6. Make them, within a cap. The Idempotency-Key makes a retry safe
curl -sX POST $BASE/projects/$PID/generate/frames -H "$AUTH" -H "$JSON" \
  -H 'Idempotency-Key: frames-001' \
  -d '{"max_credits":200}'

# 7. Poll a job
curl -s $BASE/jobs/$JID -H "$AUTH"

# 8. Export the film
curl -sX POST $BASE/projects/$PID/export -H "$AUTH"

Retrying a paid call with the same Idempotency-Key and body returns the first answer (with Idempotent-Replayed: true) instead of running again. Answers are kept for 24 hours.

Endpoints

The paths below are under https://getziztu.com/api/v1, except the API key routes. The OpenAPI spec has the request shapes.

Projects

MethodPathNotes
GET/projectsList all projects
POST/projects{ name, aspect?, presetId? }
GET/projects/:pidFull project + ?full=1 for raw document
PATCH/projects/:pidPartial update
DELETE/projects/:pidDeletes project and media

Characters and places

MethodPathNotes
POST/projects/:pid/characters{ name, description, color, looks, ... }
PATCH/projects/:pid/characters/:cid
DELETE/projects/:pid/characters/:cid
POST/projects/:pid/places{ name, description, time_of_day, weather, mood, ... }
PATCH/projects/:pid/places/:lid
DELETE/projects/:pid/places/:lid

Shots

MethodPathNotes
GET/projects/:pid/shotsAll shots in order
POST/projects/:pid/shots{ title, idea, duration, character_ids, place_id, ... }
PATCH/projects/:pid/shots/:sid
DELETE/projects/:pid/shots/:sid

Music tracks

MethodPathNotes
GET/projects/:pid/music
POST/projects/:pid/music{ name, start, length, prompt, model, ... }
PATCH/projects/:pid/music/:mid
DELETE/projects/:pid/music/:mid

Director AI

MethodPathNotes
POST/projects/:pid/director/planScene specs only: { text }
POST/projects/:pid/director/chatPlan or change the project in plain words: { message }. The reply has an id and proposed actions
POST/projects/:pid/director/messages/:mid/apply-allApply all free actions from a reply
POST/projects/:pid/director/messages/:mid/actions/:aid/applyApply one action

Paid generation

MethodPathNotes
POST/projects/:pid/generate/framesFirst-frame images. shot_ids?, count?, model?
POST/projects/:pid/generate/animateClips. shot_ids?
POST/projects/:pid/generate/musicMusic. track_ids?
POST/projects/:pid/generate/character-imagescharacter_id, kind?, count?, model?
POST/projects/:pid/generate/place-platesplace_id, count?, model?
POST/projects/:pid/generate/director-actionmessage_id, action_id
POST/projects/:pid/quoteExact price, no spend. { operation, ... }

Export and media

MethodPathNotes
POST/projects/:pid/exportStart ffmpeg export (free)
GET/projects/:pid/export/planLength, clips, drafts
GET/projects/:pid/media/:aid/fileDownload a media asset (needs export scope on SaaS)

Jobs

MethodPathNotes
GET/jobs?project_id=List jobs
GET/jobs/:jidSingle job
POST/jobs/:jid/cancelCancel a running job

Credits

MethodPathNotes
GET/creditsLocal: USD spent/budget. SaaS: credits + plan

Tools

MethodPathNotes
GET/toolsList all tools
POST/tools/recommend{ query } - AI-powered tool recommender
GET/tools/:tool/runsList runs
POST/tools/:tool/runsStart a run. { prompt, max_credits, settings?, ... }
GET/tools/:tool/runs/:pidRun status (gate, question, outputs)
POST/tools/:tool/runs/:pid/approveRaise budget: { max_credits, confirm? }
POST/tools/:tool/runs/:pid/stopStop a run
POST/tools/:tool/runs/:pid/messageSend text or answer a question
POST/tools/:tool/quoteQuote a run (no spend): { prompt, settings? }

API keys

MethodPathNotes
GET/api/account/api-keysList your keys
POST/api/account/api-keysCreate: { name, scopes?, rate_limit_per_min? }
DELETE/api/account/api-keys/:idRevoke

The API key routes work with a signed-in session, not with an API key. A key cannot make other keys.

Errors

An error
{
  "error": {
    "code": "over_max_credits",
    "message": "This would spend 150 credits, more than max_credits (100). Nothing more was started.",
    "max_credits": 100,
    "needed": 150
  }
}

Every error has a code you can switch on and a message you can show. Spend errors also carry the quote.

CodeHTTPWhat it means
unauthenticated401No API key was sent.
invalid_api_key401The key is not valid or was revoked.
insufficient_scope403The key lacks the scope the call needs (scope says which).
rate_limited429Too many requests. Wait for Retry-After seconds.
bad_request400A field is missing or wrong (field says which).
max_credits_required400A paid call came without max_credits. The error carries the quote and says what to send.
over_max_credits402The call would cost more than max_credits (needed is the price). Nothing was started.
confirm_required409The call is above 500 credits or needs a review. Send confirm: true.
blocked422One or more shots cannot run yet. Fix them, or send skip_blocked: true to run the rest.
nothing_to_do422There is nothing to make: every shot already has one, or none was named.
not_found404The project, shot, job or run does not exist for this account.
idempotency_key_reused422The Idempotency-Key was used with a different request.
idempotency_in_progress409A request with this Idempotency-Key is still running.
tool_unavailable503The Studio app is not available right now.

A paid call from an account with too few credits is refused with HTTP 402 before anything starts.

Rate limits

By default 120 requests a minute per key, and 30 paid POSTs a minute. A response carries X-RateLimit-Limit and X-RateLimit-Remaining. When you pass the limit you get HTTP 429 and a Retry-After header with the seconds to wait.

Frequently asked questions

How do I get a Ziztu API key?

Sign in to the Studio, open Settings, then API keys. Name the key, pick its scopes (read, generate, export) and copy it. It is shown once and starts with sk_sakuga_.

How do I check a price before I spend?

Send dry_run: true with max_credits to a generate endpoint, or call the quote endpoint. You get the exact credits and nothing is started. Above 500 credits a real call also needs confirm: true.

Is there an OpenAPI spec?

Yes. https://getziztu.com/api/v1/openapi.json is an OpenAPI 3.1 document.

What are the rate limits?

By default 120 requests a minute per key and 30 paid requests a minute.

Can I use the API with the free credits?

A key spends the credits of the account that made it. New accounts get 40 free credits. Plans start at $12 a month for 1,000 credits.

Make a key and send your first call.

New accounts get 40 free credits. No credit card required.