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.
https://zadifyai.cam/api/public/v1Quickstart
Create a key in the dashboard, export it, then make your first call.
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.
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.
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.
modelstring, requiredflyx-1.0 or flyx-1.0-hdreference_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 MBpromptstring, optionalOnly if you want to describe the look in words. Omit it entirely when you send a reference photoenhance_promptboolean, optionalAuto-expands a text prompt. Irrelevant and safely omitted when there is no promptttl_secondsinteger, optionalSession lifetime, 60–1800. Defaults to 600curl -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"
}'{
"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.
# 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_urllivekit_joinclient → serverStarts negotiation. Send it as soon as the socket opensset_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 requiredlivekit_room_infoserver → clientMedia credentials: { livekit_url, token, room_name }prompt_ack / set_image_ackserver → clientConfirms a style changegeneration_started / generation_tick / generation_endedserver → clientStream lifecycle and billed secondserrorserver → client{ code, error } — see the close codes belowFailures 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.
modelstring, requiredflyx-1.0-video or flyx-1.0-imagepromptstring, requiredWhat the output should look likeinput_urlstring, requiredPublicly reachable source video or image URLwebhook_urlstring, optionalCalled when the job reaches a final statuscurl -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"
}'{
"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.
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.
curl https://zadifyai.cam/api/public/v1/account -H "Authorization: Bearer $ZADIFY_API_KEY"{
"object": "account",
"credits_remaining": 4855,
"key": { "name": "Production server", "environment": "live", "masked": "kn_live_a1b2...9xyz" }
}Models
Credit price is fixed per model.
Live camera transformation from a single reference photo at 720p.
The same realtime transformation at 1080p for desktop capture.
Asynchronous prompt-driven transformation of an uploaded clip.
Single-frame restyling and editing from a prompt.
Errors
Errors use standard HTTP statuses with a machine-readable type.
400 invalid_request_errorMissing or malformed parameters401 authentication_errorMissing, unknown or revoked API key402 insufficient_creditsBalance too low for the requested model404 not_foundThe job id does not belong to your account502 upstream_errorTransformation backend unavailable; credits refunded{
"error": {
"type": "insufficient_credits",
"message": "Not enough credits for this job."
}
}