GET /v1/virtual-tryon/jobs/{job_id} endpoint.
The standard POST /v1/virtual-tryon endpoint accepts one garment at a time. If you want to dress a model in a coordinated outfit — a shirt and trousers — you previously had to run two separate calls and thread the intermediate result manually.
The /outfit endpoint removes that complexity. Send the person photo, the top garment, and the bottom garment in a single request. The API runs two sequential VTON passes internally and returns one composite result.
/v1/virtual-tryon/jobs/{job_id} as usual. No extra endpoints to call.POST https://api.pixelapi.dev/v1/virtual-tryon/outfit
Authorization: Bearer <your_api_key>
Content-Type: application/json
| Field | Type | Required | Description |
|---|---|---|---|
person_image | string (base64) | required | Base64-encoded JPEG, PNG, or WebP of the person / model. Must show full or half-body (not a headshot). Max 10 MB decoded. |
upperbody_garment | string (base64) | required | Base64-encoded garment photo of the top (shirt, jacket, blouse, hoodie). Flat-lay or product shot on a plain background. Max 10 MB decoded. |
lowerbody_garment | string (base64) | required | Base64-encoded garment photo of the bottom (trousers, jeans, skirt). Flat-lay or product shot. Full-length pants produce the best results; shorts may render with limited leg coverage. |
n_steps | integer | optional | Diffusion steps per stage (1–50, default 40, minimum enforced to 40 for quality). |
image_scale | float | optional | Guidance scale (0.1–10.0, default 2.5, minimum enforced to 2.5). |
webhook_url | string | optional | HTTPS URL to POST the completed result to. Must be a valid HTTPS endpoint. |
{
"job_id": "1bf21d2d-7432-4930-a6d3-e941d2157d80",
"status": "processing",
"eta_seconds": 90,
"poll_url": "/v1/virtual-tryon/jobs/1bf21d2d-7432-4930-a6d3-e941d2157d80",
"credits_used": 22,
"processing_stages": 2,
"stage_order": "lowerbody first, then upperbody layered over result"
}
| Field | Description |
|---|---|
job_id | UUID of the parent job. Use this in the poll endpoint. |
status | "processing" — the chain is running; poll for completion. |
eta_seconds | Estimated total time for both stages (~90s under normal load). |
poll_url | Relative path to GET /v1/virtual-tryon/jobs/{job_id}. |
credits_used | 22 credits on standard plans (2× the single-garment cost of 11cr). 500 credits on SCALE plans (2× 250cr). |
processing_stages | Always 2. |
stage_order | Informational string confirming processing order. |
Use the standard job endpoint — no changes needed:
GET https://api.pixelapi.dev/v1/virtual-tryon/jobs/{job_id}
Authorization: Bearer <your_api_key>
When status === "completed", the output_url field contains the final composite image URL (or result_image_b64 for inline base64). On failure, credits are auto-refunded.
| Plan | Credits per outfit job | Approx. time |
|---|---|---|
| Free / Starter / Pro | 22 credits (2× 11cr) | ~90s (two GPU passes) |
| SCALE | 500 credits (2× 250cr) | ~30–45s (managed fast lane) |
All the same quality and safety gates from the standard endpoint are applied to both garments and to the person photo:
upperbody_garment must not be pants; lowerbody_garment must not be a top)No credits are charged if any gate rejects the input.
PERSON=$(base64 -w0 person.jpg)
TOP=$(base64 -w0 shirt.jpg)
BOTTOM=$(base64 -w0 trousers.jpg)
curl -s -X POST https://api.pixelapi.dev/v1/virtual-tryon/outfit \
-H "Authorization: Bearer $PIXELAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"person_image": "'"$PERSON"'",
"upperbody_garment": "'"$TOP"'",
"lowerbody_garment": "'"$BOTTOM"'"
}' | jq .job_id
import requests, base64, time
def b64(path):
return base64.b64encode(open(path,'rb').read()).decode()
resp = requests.post(
"https://api.pixelapi.dev/v1/virtual-tryon/outfit",
headers={"Authorization": "Bearer " + API_KEY},
json={
"person_image": b64("person.jpg"),
"upperbody_garment": b64("shirt.jpg"),
"lowerbody_garment": b64("trousers.jpg"),
},
)
job_id = resp.json()["job_id"]
# Poll until done
while True:
time.sleep(5)
r = requests.get(
f"https://api.pixelapi.dev/v1/virtual-tryon/jobs/{job_id}",
headers={"Authorization": "Bearer " + API_KEY},
).json()
if r["status"] == "completed":
print("Result:", r["output_url"])
break
if r["status"] == "failed":
print("Failed:", r["error_message"])
break
print(f" {r['status']} — ETA {r.get('eta_seconds','?')}s")
The /outfit endpoint is a plain JSON REST call, identical in authentication and polling to the existing single-garment endpoint. From the Lensora Android app:
/v1/virtual-tryon/outfit with Authorization: Bearer <user_token>./v1/virtual-tryon/jobs/{job_id} every 5 seconds. ETA is ~90s.status === "completed". Show the user a cost notice of 22 credits before submitting (2× the single-garment cost)./v1/auth/token.Last updated: 2026-07-13 · [email protected]