AI Custom Design API
Let your customers submit any photo, a memory, a story, art, or a favorite person, and AI turns it into a high-fashion piece in your design style, ready for you to make and ship. No catalog, no StyleMe reading required. This is the Runway Edit feature from the ZukMe app, available here as an API.
Quickstart
Customer's photo
memory, story, art, or portrait
Your design style
outfit + scene
1 creditHigh-fashion piece
photorealistic image
- 1Create an API key in the API Dashboard, then contact our team to get credits added — a new key starts with none.
- 2Submit your image plus outfit and scene direction to
POST /api/v1/runway-edit. - 3Poll with the returned
jobIdevery 2–3s until done (typically 30–90s).
Base URL
https://zukme.comAll endpoints below are relative to this base URL.
Authentication
Every request needs your API key as a bearer token — create and manage keys in the API Dashboard. The raw key is shown once; only its hash is stored.
Authorization: Bearer zk_live_<your key>Missing, malformed, or revoked key → 401:
{ "error": "Invalid or missing API key. Pass it as \"Authorization: Bearer zk_live_...\"." }Rate limits
30 requests per minute per key (submit and poll both count). Over the limit → 429:
{ "error": "Rate limit exceeded.", "retryAfterSeconds": 12 }Credits
Each successful submission costs 1 credit, deducted at submit and refunded automatically if generation fails. Polling is always free. A new API key starts with 0 credits — API and embed-widget usage spends from your account's bonus credit balance only, never your app subscription's monthly quota. Contact our team to get bonus credits added before building against this in production. Check your balance in the API Dashboard.
Errors
| Field | Type | Description |
|---|---|---|
400 | Bad Request | Missing or invalid fields in the request body. |
401 | Unauthorized | Missing, malformed, or revoked API key. |
402 | Payment Required | Credits exhausted (code CREDITS_EXHAUSTED), with your current looks/bonus/total balance in the body. |
404 | Not Found | jobId does not exist (expired, wrong id, or never submitted). |
429 | Too Many Requests | Rate limit exceeded for this key. See retryAfterSeconds. |
Example 402 body:
{
"error": "CREDITS_EXHAUSTED",
"code": "CREDITS_EXHAUSTED",
"looks": 0,
"bonus": 0,
"total": 0
}Submit
/api/v1/runway-editSubmit| Field | Type | Description |
|---|---|---|
artPhotoBase64required | string | Base64-encoded source image (art, photo, or design) the outfit is built from. |
outfitNamerequired | string | Short name for the outfit, e.g. "Tailored Blazer Set". |
outfitDirectionrequired | string | Free-text description of the garment(s): cut, pieces, silhouette. Up to 3000 characters. |
sceneNamerequired | string | Short name for the scene/location, e.g. "Golden Hour Rooftop". |
styleDirectionrequired | string | Free-text mood/style direction for the scene and shot. Up to 2000 characters. |
size | "S" | "M" | "L" | "XL" | "XXL" | "XXXL" | Model build size. Defaults to "M". |
gender | "Male" | "Female" | "Neutral" | Model gender direction. Defaults to "Neutral". |
ageGroup | "Adult" | "New Wave" | "New Wave" generates a teen model profile. Defaults to "Adult". |
callbackUrl | string | Optional webhook — see below. |
Response:
{ "ok": true, "jobId": "b3f1...", "status": "processing" }Poll
/api/v1/runway-editPoll| Field | Type | Description |
|---|---|---|
actionrequired | "poll" | Selects the poll branch. |
jobIdrequired | string | The jobId returned by the submit call. |
Response, by status:
// processing
{ "status": "processing", "stage": "t2i" }
// done
{ "ok": true, "status": "done", "imageUrl": "https://..." }
// error (credit already refunded)
{ "status": "error", "error": "The AI model failed on this image. Please try again." }Callbacks (webhooks)
Pass a callbackUrl on submit to also get the completed payload POSTed there when the job finishes — in addition to, never instead of, polling. Best-effort, no retries: keep polling as your source of truth. Must be a public http(s) URL; localhost and private network addresses are rejected.
Full example
curl https://zukme.com/api/v1/runway-edit \
-X POST \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-d '{
"artPhotoBase64": "<base64>",
"outfitName": "Tailored Blazer Set",
"outfitDirection": "structured double-breasted blazer, wide-leg trousers",
"sceneName": "Golden Hour Rooftop",
"styleDirection": "warm, cinematic, editorial"
}'
# → { "ok": true, "jobId": "b3f1...", "status": "processing" }
curl https://zukme.com/api/v1/runway-edit \
-X POST \
-H "Authorization: Bearer zk_live_..." \
-H "Content-Type: application/json" \
-d '{ "action": "poll", "jobId": "b3f1..." }'
# → { "ok": true, "status": "done", "imageUrl": "https://..." }const KEY = process.env.ZUKME_API_KEY;
const BASE = "https://zukme.com/api/v1/runway-edit";
async function call(body) {
const res = await fetch(BASE, {
method: "POST",
headers: { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" },
body: JSON.stringify(body),
});
return res.json();
}
const submitted = await call({
artPhotoBase64,
outfitName: "Tailored Blazer Set",
outfitDirection: "structured double-breasted blazer, wide-leg trousers",
sceneName: "Golden Hour Rooftop",
styleDirection: "warm, cinematic, editorial",
});
let result;
while (true) {
result = await call({ action: "poll", jobId: submitted.jobId });
if (result.status === "done" || result.status === "error") break;
await new Promise((r) => setTimeout(r, 2500));
}
console.log(result); // { ok: true, status: "done", imageUrl: "..." }Want real, purchasable garments on your user instead of an original design?