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.
- Open the Studio at getziztu.com/app and sign in. Open Settings, then API keys.
- Name the key (for example "Claude Code") and pick its scopes:
readto look around,generateto plan and make things,exportto download films. - Copy the key. It starts with
sk_sakuga_and is shown once.
Send the key on every request, in either header:
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:
{
"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_creditsis 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: trueor thequotetool returns the exact credits and starts nothing. The quote also lists any shot that is blocked, and why. - Retries are safe with an
Idempotency-Keyheader: the same key and body returns the first answer instead of running twice. - Scope the key. A key without
generatecannot start paid work. Make areadkey 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.
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
| Method | Path | Notes |
|---|---|---|
| GET | /projects | List all projects |
| POST | /projects | { name, aspect?, presetId? } |
| GET | /projects/:pid | Full project + ?full=1 for raw document |
| PATCH | /projects/:pid | Partial update |
| DELETE | /projects/:pid | Deletes project and media |
Characters and places
| Method | Path | Notes |
|---|---|---|
| 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
| Method | Path | Notes |
|---|---|---|
| GET | /projects/:pid/shots | All 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
| Method | Path | Notes |
|---|---|---|
| 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
| Method | Path | Notes |
|---|---|---|
| POST | /projects/:pid/director/plan | Scene specs only: { text } |
| POST | /projects/:pid/director/chat | Plan or change the project in plain words: { message }. The reply has an id and proposed actions |
| POST | /projects/:pid/director/messages/:mid/apply-all | Apply all free actions from a reply |
| POST | /projects/:pid/director/messages/:mid/actions/:aid/apply | Apply one action |
Paid generation
| Method | Path | Notes |
|---|---|---|
| POST | /projects/:pid/generate/frames | First-frame images. shot_ids?, count?, model? |
| POST | /projects/:pid/generate/animate | Clips. shot_ids? |
| POST | /projects/:pid/generate/music | Music. track_ids? |
| POST | /projects/:pid/generate/character-images | character_id, kind?, count?, model? |
| POST | /projects/:pid/generate/place-plates | place_id, count?, model? |
| POST | /projects/:pid/generate/director-action | message_id, action_id |
| POST | /projects/:pid/quote | Exact price, no spend. { operation, ... } |
Export and media
| Method | Path | Notes |
|---|---|---|
| POST | /projects/:pid/export | Start ffmpeg export (free) |
| GET | /projects/:pid/export/plan | Length, clips, drafts |
| GET | /projects/:pid/media/:aid/file | Download a media asset (needs export scope on SaaS) |
Jobs
| Method | Path | Notes |
|---|---|---|
| GET | /jobs?project_id= | List jobs |
| GET | /jobs/:jid | Single job |
| POST | /jobs/:jid/cancel | Cancel a running job |
Credits
| Method | Path | Notes |
|---|---|---|
| GET | /credits | Local: USD spent/budget. SaaS: credits + plan |
Tools
| Method | Path | Notes |
|---|---|---|
| GET | /tools | List all tools |
| POST | /tools/recommend | { query } - AI-powered tool recommender |
| GET | /tools/:tool/runs | List runs |
| POST | /tools/:tool/runs | Start a run. { prompt, max_credits, settings?, ... } |
| GET | /tools/:tool/runs/:pid | Run status (gate, question, outputs) |
| POST | /tools/:tool/runs/:pid/approve | Raise budget: { max_credits, confirm? } |
| POST | /tools/:tool/runs/:pid/stop | Stop a run |
| POST | /tools/:tool/runs/:pid/message | Send text or answer a question |
| POST | /tools/:tool/quote | Quote a run (no spend): { prompt, settings? } |
API keys
| Method | Path | Notes |
|---|---|---|
| GET | /api/account/api-keys | List your keys |
| POST | /api/account/api-keys | Create: { name, scopes?, rate_limit_per_min? } |
| DELETE | /api/account/api-keys/:id | Revoke |
The API key routes work with a signed-in session, not with an API key. A key cannot make other keys.
Errors
{
"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.
| Code | HTTP | What it means |
|---|---|---|
unauthenticated | 401 | No API key was sent. |
invalid_api_key | 401 | The key is not valid or was revoked. |
insufficient_scope | 403 | The key lacks the scope the call needs (scope says which). |
rate_limited | 429 | Too many requests. Wait for Retry-After seconds. |
bad_request | 400 | A field is missing or wrong (field says which). |
max_credits_required | 400 | A paid call came without max_credits. The error carries the quote and says what to send. |
over_max_credits | 402 | The call would cost more than max_credits (needed is the price). Nothing was started. |
confirm_required | 409 | The call is above 500 credits or needs a review. Send confirm: true. |
blocked | 422 | One or more shots cannot run yet. Fix them, or send skip_blocked: true to run the rest. |
nothing_to_do | 422 | There is nothing to make: every shot already has one, or none was named. |
not_found | 404 | The project, shot, job or run does not exist for this account. |
idempotency_key_reused | 422 | The Idempotency-Key was used with a different request. |
idempotency_in_progress | 409 | A request with this Idempotency-Key is still running. |
tool_unavailable | 503 | The 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.