Loading…

ZSky AI Developer API

Developer API access for Max-tier subscribers. Same generation pipeline as the web app: photographic image generation, video with synchronized audio, AI Creative Director output. Flat $99/mo includes 300 videos + 1000 images per calendar month. Allowance resets on the 1st of each calendar month. Higher volume available on request.

Beta status: the API is currently in private beta for hand-picked Max customers. To request an API key, email [email protected] with a brief description of your use case and expected daily volume.

Authentication

Every request must include an X-API-Key header containing a key issued to you. Keys are long-lived; rotate them from this dashboard or by calling POST /v1/keys/rotate. Lost keys cannot be recovered — rotation issues a new one and immediately invalidates the previous.

curl https://zsky.ai/v1/usage \
  -H "X-API-Key: zsky_live_..."
Keep your key private. Anyone with your key can run generations against your account and consume your monthly allowance. Store in a secrets manager, never commit to source control, never expose in client-side code.

Endpoints

MethodPathPurpose
POST/v1/images/generateCreate an image (text-to-image)
POST/v1/videos/generateCreate a video (text-to-video)
GET/v1/jobs/<id>Poll job status, get signed result URL
DELETE/v1/jobs/<id>Purge the result from storage
GET/v1/usageCurrent-month allowance counters
POST/v1/keys/rotateIssue a new key, invalidate current

POST /v1/images/generate

curl -X POST https://zsky.ai/v1/images/generate \
  -H "X-API-Key: zsky_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A neon-lit alley in Tokyo at dusk, photorealistic",
    "width": 1024,
    "height": 1024
  }'

# Response (HTTP 200):
{
  "job_id": "5f3...",
  "status": "queued",
  "kind": "image",
  "poll_url": "/v1/jobs/5f3..."
}

Parameters:

POST /v1/videos/generate

curl -X POST https://zsky.ai/v1/videos/generate \
  -H "X-API-Key: zsky_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A solitary lighthouse beam sweeping across choppy black sea, cinematic",
    "length": 121
  }'

# Response (HTTP 200):
{
  "job_id": "8a1...",
  "status": "queued",
  "kind": "video",
  "poll_url": "/v1/jobs/8a1..."
}

Parameters:

Videos take ~60 seconds to render. Use the poll_url to check status. Image-to-video (uploading a starting frame) is not yet supported in v1 — coming in v2.

GET /v1/jobs/<id>

curl https://zsky.ai/v1/jobs/8a1... -H "X-API-Key: zsky_live_..."

# While queued/running:
{ "job_id": "8a1...", "status": "queued", "kind": "video" }

# When completed:
{
  "job_id": "8a1...",
  "status": "completed",
  "kind": "video",
  "result_url": "https://...r2.cloudflarestorage.com/...&X-Amz-Signature=...",
  "expires_in": 86400
}

# If blocked by safety:
{
  "job_id": "8a1...",
  "status": "blocked",
  "kind": "video",
  "error": "Sorry — our safety check stopped this video..."
}

result_url is a 24-hour signed download URL pointing directly at our storage. Download it once and persist locally if you need the bytes longer.

DELETE /v1/jobs/<id>

Purges the generated asset from our storage before the 7-day auto-delete. Useful when you've downloaded the bytes and want them gone immediately. Returns HTTP 204 on success, 404 if the job doesn't exist or isn't yours.

GET /v1/usage

curl https://zsky.ai/v1/usage -H "X-API-Key: zsky_live_..."

# Response:
{
  "videos_used": 47,
  "videos_overage": 0,
  "images_used": 180,
  "images_overage": 0,
  "overage_charged_cents": 0,
  "base_videos_allowance": 300,
  "base_images_allowance": 1000,
  "month_start": "2026-05-01"
}

POST /v1/keys/rotate

Issues a new key and invalidates the current one. Save the new key immediately — it cannot be recovered if lost. The response includes a one-time-shown plaintext value.

Rate Limits & Allowances

Monthly base — videos300 per calendar month (UTC)
Monthly base — images1,000 per calendar month (UTC)
RolloverNone — unused allowance does NOT carry over to next month
Reset1st of each calendar month at 00:00 UTC
Concurrent jobs3 per API key
Burst20 requests per minute per key
Daily soft cap50 videos / 200 images per UTC day per key (lift on request)
Base allowance: no rollover. The 300 videos and 1000 images reset to 0 on the 1st of each calendar month. Unused base allowance is forfeited.

Overage budget: does roll over. If you opt in to overage and set a monthly cap (e.g. $50), any unused overage budget carries over to the following month. Use it or save it across months.

If you need consistently higher monthly volume, enable overage (one-click via your dashboard once Plan 2 lands; until then, email [email protected]).

Beyond the monthly base, overage is opt-in only. Default state is hard-stop at the allowance. To enable overage, set a monthly budget cap from your dashboard (Plan 2 — coming soon); until then, contact [email protected].

Overage pricing when enabled: $0.50 per video, $0.05 per image.

Storage & Retention

Safety

Every API request flows through the same safety pipeline as our web app: input checks on prompts, output checks on generated content. Blocked generations return status blocked with a human-readable reason — they still count against your monthly allowance because the GPU work was performed.

Repeated rejected requests (more than 50% of the last 30 minutes' attempts, minimum 10 events) trigger an automatic 24-hour suspension on the API key. If suspended, you'll get HTTP 403 until the window clears. Email support if you believe the suspension is in error.

Error Codes

StatusMeaning
200OK
204No content (DELETE success)
400Malformed request body or invalid params
401Missing or invalid API key
403API key suspended
404Job not found (or not owned by you)
429Rate limit hit OR monthly allowance reached without overage
451Generation blocked by safety filter
500Internal error — please retry
503Workers unavailable; queued — please retry shortly

Sample Python Client

#!/usr/bin/env python3
"""Minimal ZSky API client — generate an image, poll, download."""
import os, time, json, urllib.request

API = "https://zsky.ai"
KEY = os.environ["ZSKY_API_KEY"]

def call(method, path, body=None):
    req = urllib.request.Request(
        f"{API}{path}",
        data=json.dumps(body).encode() if body else None,
        headers={"X-API-Key": KEY, "Content-Type": "application/json"},
        method=method,
    )
    with urllib.request.urlopen(req, timeout=30) as r:
        return json.loads(r.read())

def generate_image(prompt):
    job = call("POST", "/v1/images/generate", {"prompt": prompt})
    job_id = job["job_id"]
    while True:
        time.sleep(2)
        state = call("GET", f"/v1/jobs/{job_id}")
        if state["status"] in ("completed", "failed", "blocked"):
            return state

state = generate_image("A coffee cup on a wooden table, photorealistic")
if state["status"] == "completed":
    print(f"Result: {state['result_url']}")
    urllib.request.urlretrieve(state["result_url"], "out.webp")
else:
    print(f"Failed: {state.get('error')}")

Versioning & Stability

The v1 surface is stable. Breaking changes will ship under /v2. Subscribe to changes by emailing [email protected].

Support

Bugs, questions, key issuance, daily-cap lifts — email [email protected]. Mention your account email so we can verify ownership.