API v1

Zadify AI API reference

Realtime video editing, built for live streams. Start a session, connect your camera, and the live video is edited to match a reference photo — no text prompt needed. Pass a single reference_image_url and the face, body and overall look from that photo are mapped onto the camera feed in realtime. A text prompt is entirely optional. All requests are JSON over HTTPS and authenticated with a secret API key.

text
https://zadifyai.cam/api/public/v1

Quickstart

Create a key in the dashboard, export it, then make your first call.

bash
export ZADIFY_API_KEY="kn_live_..."

curl -X POST https://zadifyai.cam/api/public/v1/realtime/sessions \
  -H "Authorization: Bearer $ZADIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"flyx-1.0"}'

How it works

Two channels: a control socket on our host, and peer-to-peer WebRTC for the video itself. This is the exact shape of a working integration.

text
1. MINT (your server)
   POST https://zadifyai.cam/api/public/v1/realtime/sessions
   Authorization: Bearer $ZADIFY_API_KEY
   { "model": "flyx-1.0",
     "reference_image_url": "https://example.com/character.jpg" }
   -> { "websocket_url": "wss://zadifyai.cam/api/public/v1/realtime/stream?token=kns_..." }

2. CONTROL CHANNEL (browser)
   connect  wss://zadifyai.cam/api/public/v1/realtime/stream?token=kns_...
   send     { "type": "livekit_join" }
   receive  { "type": "livekit_room_info", "livekit_url", "token", "room_name" }

3. MEDIA TRANSPORT (browser, WebRTC via livekit-client)
   const room = new Room()
   room.on(RoomEvent.TrackSubscribed, ...)   // attach transformed video
   await room.connect(livekit_url, token)
   await room.localParticipant.publishTrack(videoTrack, { name: "camera" })

Your secret API key stays on your server — the browser only ever holds the short-lived kns_ session token. Camera frames never reach zadifyai.cam; only the control messages do.

Authentication

Send your secret key as a bearer token. Keys are server-side only — never ship one to a browser or mobile app.

bash
curl https://zadifyai.cam/api/public/v1/account \
  -H "Authorization: Bearer $ZADIFY_API_KEY"

A revoked or unknown key returns 401 authentication_error. For untrusted clients, mint an ephemeral realtime session instead of sharing the key.

POST /realtime/sessions

Mints a short-lived session secret for a realtime stream. Send a reference photo and the live video is edited to match it — no prompt required. Charged 25 credits per session.

Parameters
Request parameters
modelstring, requiredflyx-1.0 or flyx-1.0-hd
reference_image_urlstring, recommendedPublicly reachable photo the stream is edited to match (character, outfit, scene). Drives the transformation on its own — no prompt needed. Max 8 MB
promptstring, optionalOnly if you want to describe the look in words. Omit it entirely when you send a reference photo
enhance_promptboolean, optionalAuto-expands a text prompt. Irrelevant and safely omitted when there is no prompt
ttl_secondsinteger, optionalSession lifetime, 60–1800. Defaults to 600
bash
curl -X POST https://zadifyai.cam/api/public/v1/realtime/sessions \
  -H "Authorization: Bearer $ZADIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flyx-1.0",
    "reference_image_url": "https://example.com/character.jpg"
  }'
json
{
  "id": "3f0c...",
  "object": "realtime.session",
  "model": "flyx-1.0",
  "prompt": null,
  "reference_image_url": "https://example.com/character.jpg",
  "client_secret": { "value": "kns_...", "expires_at": "2026-09-22T13:20:00.000Z" },
  "websocket_url": "wss://zadifyai.cam/api/public/v1/realtime/stream?token=kns_...",
  "expires_at": "2026-09-22T13:20:00.000Z",
  "credits_charged": 25,
  "credits_remaining": 4975
}

Hand websocket_url (or just client_secret.value) to the browser that owns the camera. The session secret is single-purpose, expires with ttl_seconds, and never exposes your secret API key to the client. The reference photo you set here is applied the moment the stream opens — no prompt is sent, and none is needed.

Streaming from the browser

Connect to the session socket, publish the camera, and render the edited stream. Video travels peer-to-peer, so latency stays low and your server carries only the control channel.

Install the media client with npm i livekit-client. The socket is a control channel: you send a join message, receive the room credentials, then publish and subscribe. Frames are never uploaded to the API host. No prompt message is ever required — the reference photo from the session already drives the transformation.

bash
# 1. your server mints the session (reference photo only, no prompt)
SESSION=$(curl -s -X POST https://zadifyai.cam/api/public/v1/realtime/sessions \
  -H "Authorization: Bearer $ZADIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"flyx-1.0","reference_image_url":"https://example.com/character.jpg"}')

# 2. pass session.websocket_url to the browser (see the Node.js tab)
echo "$SESSION" | jq -r .websocket_url
Parameters
Request parameters
livekit_joinclient → serverStarts negotiation. Send it as soon as the socket opens
set_imageclient → server, optionalSwaps the reference photo mid-stream: { image_data (base64) }
promptclient → server, optionalOnly if you want to steer with words: { prompt, enhance_prompt? }. Never required
livekit_room_infoserver → clientMedia credentials: { livekit_url, token, room_name }
prompt_ack / set_image_ackserver → clientConfirms a style change
generation_started / generation_tick / generation_endedserver → clientStream lifecycle and billed seconds
errorserver → client{ code, error } — see the close codes below

Failures arrive as an error message followed by a close code: 4001 authentication_error (missing or unknown session token), 4003 session_expired or session_closed, 4011 upstream_error (streaming backend unavailable). A reference photo that cannot be downloaded sends a non-fatal reference_image_error and the stream continues untransformed, so retry with set_image or a reachable URL.

POST /transforms

Transforms a video or an image. Image jobs return status succeeded with the finished output_url in the same response; video jobs return 202 with a job id to poll.

Parameters
Request parameters
modelstring, requiredflyx-1.0-video or flyx-1.0-image
promptstring, requiredWhat the output should look like
input_urlstring, requiredPublicly reachable source video or image URL
webhook_urlstring, optionalCalled when the job reaches a final status
bash
curl -X POST https://zadifyai.cam/api/public/v1/transforms \
  -H "Authorization: Bearer $ZADIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flyx-1.0-video",
    "prompt": "cyberpunk neon, rain-slicked streets",
    "input_url": "https://cdn.example.com/clip.mp4"
  }'
json
{
  "id": "job_8c21...",
  "object": "transform.job",
  "model": "flyx-1.0-video",
  "kind": "video",
  "status": "processing",
  "output_url": null,
  "credits_charged": 120,
  "credits_remaining": 4855
}

If the transformation backend rejects a job, the call returns 502 upstream_error and your credits are refunded automatically.

GET /transforms/{id}

Fetches the current status of a job. Poll every few seconds until status is succeeded or failed.

bash
curl https://zadifyai.cam/api/public/v1/transforms/job_8c21 \
  -H "Authorization: Bearer $ZADIFY_API_KEY"

GET /account

Returns the credit balance and metadata for the key making the request. Free of charge.

bash
curl https://zadifyai.cam/api/public/v1/account -H "Authorization: Bearer $ZADIFY_API_KEY"
json
{
  "object": "account",
  "credits_remaining": 4855,
  "key": { "name": "Production server", "environment": "live", "masked": "kn_live_a1b2...9xyz" }
}

Models

Credit price is fixed per model.

flyx-1.0

Live camera transformation from a single reference photo at 720p.

25 credits per session minute
flyx-1.0-hd

The same realtime transformation at 1080p for desktop capture.

45 credits per session minute
flyx-1.0-video

Asynchronous prompt-driven transformation of an uploaded clip.

120 credits per job
flyx-1.0-image

Single-frame restyling and editing from a prompt.

10 credits per job

Errors

Errors use standard HTTP statuses with a machine-readable type.

Parameters
Request parameters
400 invalid_request_errorMissing or malformed parameters
401 authentication_errorMissing, unknown or revoked API key
402 insufficient_creditsBalance too low for the requested model
404 not_foundThe job id does not belong to your account
502 upstream_errorTransformation backend unavailable; credits refunded
json
{
  "error": {
    "type": "insufficient_credits",
    "message": "Not enough credits for this job."
  }
}