Comparing VTON API vs CALA? PixelAPI's virtual try-on API lets developers dress any model in any garment with a single REST call — no sales call, no enterprise contract, no minimum commitment. Send a garment image and a person image, get a photorealistic composite back in under 30 seconds. $0.025 per try-on image — approximately 4× cheaper than FASHN AI, and a fraction of the cost of enterprise platforms like CALA, Zyler, or Veesual. 500 free credits, no credit card required.
Sign up, copy your key from the dashboard, and POST two base64-encoded images (garment + person). The endpoint returns a job_id. Poll until status=completed, then download your composite from output_url or read it straight from result_image_b64.
# 1. Submit the try-on job
curl -X POST https://api.pixelapi.dev/v1/virtual-tryon \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"garment_image": "'$(base64 -w0 shirt.jpg)'",
"person_image": "'$(base64 -w0 model.jpg)'",
"category": "upperbody"
}'
# Response: {"job_id":"uuid","status":"queued","eta_seconds":30,...}
# 2. Poll for the result
curl https://api.pixelapi.dev/v1/virtual-tryon/jobs/JOB_ID \
-H "Authorization: Bearer YOUR_API_KEY"
# Response: {"status":"completed","output_url":"https://...","result_image_b64":"..."}
import base64, time, requests
API_KEY = "YOUR_API_KEY"
BASE = "https://api.pixelapi.dev"
def b64(path):
with open(path, "rb") as f:
return base64.b64encode(f.read()).decode()
# Submit
resp = requests.post(f"{BASE}/v1/virtual-tryon",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"garment_image": b64("shirt.jpg"),
"person_image": b64("model.jpg"),
"category": "upperbody", # upperbody | lowerbody | dress
}
)
job_id = resp.json()["job_id"]
# Poll until done
while True:
r = requests.get(f"{BASE}/v1/virtual-tryon/jobs/{job_id}",
headers={"Authorization": f"Bearer {API_KEY}"}).json()
if r["status"] == "completed":
print("Done:", r["output_url"])
break
time.sleep(5)
import fs from "fs";
import fetch from "node-fetch";
const API_KEY = process.env.PIXELAPI_KEY;
const BASE = "https://api.pixelapi.dev";
const b64 = (path) => fs.readFileSync(path).toString("base64");
// Submit
const job = await fetch(`${BASE}/v1/virtual-tryon`, {
method: "POST",
headers: { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
garment_image: b64("shirt.jpg"),
person_image: b64("model.jpg"),
category: "upperbody",
}),
}).then(r => r.json());
// Poll
let result;
do {
await new Promise(r => setTimeout(r, 5000));
result = await fetch(`${BASE}/v1/virtual-tryon/jobs/${job.job_id}`, {
headers: { Authorization: `Bearer ${API_KEY}` },
}).then(r => r.json());
} while (result.status !== "completed");
console.log("Done:", result.output_url);
<?php
$API_KEY = getenv("PIXELAPI_KEY");
$BASE = "https://api.pixelapi.dev";
function b64($path) { return base64_encode(file_get_contents($path)); }
// Submit
$ch = curl_init("$BASE/v1/virtual-tryon");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $API_KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => json_encode([
"garment_image" => b64("shirt.jpg"),
"person_image" => b64("model.jpg"),
"category" => "upperbody",
]),
]);
$job = json_decode(curl_exec($ch), true);
$job_id = $job["job_id"];
// Poll
do {
sleep(5);
$ch2 = curl_init("$BASE/v1/virtual-tryon/jobs/$job_id");
curl_setopt_array($ch2, [CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer $API_KEY"]]);
$result = json_decode(curl_exec($ch2), true);
} while ($result["status"] !== "completed");
echo $result["output_url"];
require "net/http"
require "json"
require "base64"
API_KEY = ENV["PIXELAPI_KEY"]
BASE = URI("https://api.pixelapi.dev")
def b64(path) = Base64.strict_encode64(File.binread(path))
# Submit
http = Net::HTTP.new(BASE.host, 443)
http.use_ssl = true
req = Net::HTTP::Post.new("/v1/virtual-tryon",
"Authorization" => "Bearer #{API_KEY}", "Content-Type" => "application/json")
req.body = {garment_image: b64("shirt.jpg"), person_image: b64("model.jpg"),
category: "upperbody"}.to_json
job = JSON.parse(http.request(req).body)
# Poll
loop do
sleep 5
r = JSON.parse(http.request(
Net::HTTP::Get.new("/v1/virtual-tryon/jobs/#{job['job_id']}",
"Authorization" => "Bearer #{API_KEY}")
).body)
break puts r["output_url"] if r["status"] == "completed"
end
package main
import (
"bytes"; "encoding/base64"; "encoding/json"; "fmt"
"io"; "net/http"; "os"; "time"
)
const apiKey = "YOUR_API_KEY"
const base = "https://api.pixelapi.dev"
func b64File(path string) string {
data, _ := os.ReadFile(path)
return base64.StdEncoding.EncodeToString(data)
}
func main() {
body, _ := json.Marshal(map[string]any{
"garment_image": b64File("shirt.jpg"),
"person_image": b64File("model.jpg"),
"category": "upperbody",
})
req, _ := http.NewRequest("POST", base+"/v1/virtual-tryon", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
resp, _ := http.DefaultClient.Do(req)
var job map[string]any
json.NewDecoder(resp.Body).Decode(&job)
for {
time.Sleep(5 * time.Second)
r, _ := http.NewRequest("GET", base+"/v1/virtual-tryon/jobs/"+job["job_id"].(string), nil)
r.Header.Set("Authorization", "Bearer "+apiKey)
out, _ := http.DefaultClient.Do(r)
var result map[string]any
json.NewDecoder(out.Body).Decode(&result)
if result["status"] == "completed" {
fmt.Println(result["output_url"])
break
}
io.Copy(io.Discard, out.Body)
}
}
CALA and most enterprise virtual try-on platforms require a sales engagement and do not publish per-image pricing. PixelAPI's virtual try-on API is self-serve with transparent, per-image billing — no annual commitment, no minimum spend.
| Provider | Free tier | Per try-on price | Self-serve API | Garment categories |
|---|---|---|---|---|
| PixelAPI | 500 credits, no card | $0.025 | ✓ Yes | upperbody · lowerbody · dress |
| FASHN AI | 10 complimentary credits | $0.10 (1 credit/image min.) | ✓ Yes | see fashn.ai/pricing |
| CALA | No | Contact sales | Enterprise only | see ca.la/pricing |
| Zyler | No | Contact sales | Enterprise only | see zyler.com/pricing |
| Veesual | No | Contact sales | Enterprise only | see veesual.ai/pricing |
| Outfit.ai | No | Contact sales | Enterprise only | see outfit.ai/pricing |
FASHN AI pricing verified from fashn.ai/pricing, May 2026. CALA, Zyler, Veesual, and Outfit.ai do not publish per-image API pricing — contact each vendor for a quote. PixelAPI's per-image price is set at approximately half the cheapest publicly available rival rate.
When the job is complete, output_url returns a temporary signed URL to the generated JPEG or PNG composite. Pipe it straight to your CDN, Shopify storefront, or product database. No intermediate file handling required.
If your server-side pipeline needs immediate bytes, result_image_b64 in the job response contains the full image as a base64 string — decode it and write to disk, a database, or an S3 bucket in a single step.
Set n_samples=2, 3, or 4 to get multiple output variants from a single garment + person pair. Useful for A/B testing product photos or showing multiple color-ways side-by-side.
Pass webhook_url in your request and PixelAPI will POST the completed result to your endpoint — no polling loop needed. Ideal for serverless functions, Zapier webhooks, or background job processors.
| Parameter | Type | Default | Description |
|---|---|---|---|
garment_image | string (base64) | required | Clothing item to try on — JPEG, PNG, or WebP, max 10 MB |
person_image | string (base64) | required | Model or person photo — JPEG, PNG, or WebP, max 10 MB |
category | string | upperbody | upperbody · lowerbody · dress |
n_samples | integer | 1 | Number of output images (1–4). Each costs 25 credits. |
n_steps | integer | 40 | Refinement steps (1–50). Higher = more detail, slower. |
image_scale | float | 2.0 | Prompt-following strength (0.1–10.0) |
webhook_url | string | null | POST result to this HTTPS URL when complete |
The Virtual Try-On API slots into these production workflows. Each links to a use-case setup guide:
Pair virtual try-on with AI image generation to spin up catalog shots from product photos alone — no studio, no model booking.
Auto-generate on-model product imagery for paid social and display ads without per-SKU photo shoots.
Remove garment backgrounds before feeding them into the try-on API for cleaner composites.
Combine virtual try-on with AI image editing to relight, recolor, and retouch the finished composite in one pipeline.
Upscale try-on outputs to print-quality resolution for lookbooks, billboards, and marketplace listings.
Index try-on output images in a visual search engine so shoppers can find similar garments by photo.
PixelAPI works with any HTTP client and the platforms your team already uses.
Trigger virtual try-on on product upload via Shopify webhooks. Attach composite images to product metafields automatically.
Connect virtual try-on to any app in your stack with a no-code Zapier workflow — no backend required.
Drag-and-drop virtual try-on into Make scenarios. Route job results to Google Drive, Airtable, Notion, or Slack.
Auto-populate Webflow CMS product entries with on-model try-on imagery via the Webflow API + PixelAPI webhook.
Veesual requires a 4-week enterprise onboarding. PixelAPI is self-serve in minutes at $0.025/image with a free trial.
Replicate charges per-second compute; PixelAPI charges per finished image with a predictable flat rate and auto-refund on failed jobs.
Browse the full comparison index for background removal, upscaling, image editing, and more.
The virtual try-on endpoint allows 10 requests per minute on all tiers. If you exceed the limit, the API returns HTTP 429 with a Retry-After header. Use exponential backoff starting at 5 seconds — the Python and Node SDKs handle this automatically. For bulk batch pipelines, email [email protected] to discuss higher concurrency limits.
If a job fails (bad input, NSFW rejection, or a processing error), credits are automatically refunded. You never pay for a broken result. The error_message field on the job status response describes the failure reason.
# Python — simple polling with backoff
import time, requests
def poll_vton(job_id, api_key, timeout=120):
deadline = time.time() + timeout
delay = 5
while time.time() < deadline:
r = requests.get(
f"https://api.pixelapi.dev/v1/virtual-tryon/jobs/{job_id}",
headers={"Authorization": f"Bearer {api_key}"}
).json()
if r["status"] == "completed":
return r["output_url"]
if r["status"] == "failed":
raise RuntimeError(r.get("error_message", "Job failed"))
time.sleep(delay)
delay = min(delay * 2, 30) # cap at 30s
raise TimeoutError("Job did not complete in time")
CALA (ca.la) is an enterprise fashion design and supply chain platform that includes virtual styling features as part of a broader managed service. It does not offer a self-serve API with transparent per-image pricing — engagement requires a sales conversation and custom contract. PixelAPI's virtual try-on API is a developer-first REST endpoint: sign up, copy your key, and make your first call in under five minutes. Pricing is $0.025 per try-on image with 500 free credits and no credit card required.
$0.025 per output image (25 credits at $0.001/credit). New accounts get 500 free credits — enough for 20 try-on images — with no credit card required. FASHN AI charges $0.10 per image on their self-serve plan; PixelAPI is approximately 4× cheaper. CALA, Zyler, Veesual, and Outfit.ai all require enterprise agreements with non-public pricing.
The API supports three clothing categories: upperbody (shirts, jackets, blazers, tops), lowerbody (trousers, skirts, shorts, jeans), and dress (full-length garments). Pass the category parameter in your JSON request body. The default is upperbody.
Both the garment image and the person/model image must be base64-encoded JPEG, PNG, or WebP — up to 10 MB each. Pass them as base64 strings in the JSON body. Data URL prefixes (data:image/jpeg;base64,...) are automatically stripped if present.
POST a JSON body with garment_image and person_image (both base64-encoded) to https://api.pixelapi.dev/v1/virtual-tryon with your Bearer API key. You'll receive a job_id. Poll GET /v1/virtual-tryon/jobs/{job_id} until status=completed, then download the result from output_url or read it from result_image_b64. See the Quick Start section above for ready-to-run code in 6 languages.
A single try-on (n_samples=1) typically completes in under 30 seconds. The response includes an eta_seconds field as a guide. Capacity is kept warm 24/7 — your first request is as fast as your thousandth.
Yes. Set n_samples to 2, 3, or 4. Each additional sample costs another 25 credits ($0.025). Four samples typically finish in under two minutes. Each output image is returned separately via output_url and result_image_b64.
The job status response includes output_url (a temporary signed URL to the composite image) and result_image_b64 (the same image as a base64 string). Use output_url for browser/CDN delivery and result_image_b64 for server-side pipelines that need immediate bytes.
Yes. Every new account starts with 500 free credits — enough for 20 virtual try-on images — with no credit card required. You can upgrade to a paid plan when you need more. Paid plans start at $10 for 10,000 credits ($0.001/credit).
The default limit is 10 requests per minute on all tiers. Exceeding it returns HTTP 429 with a Retry-After header. Use exponential backoff starting at 5 seconds. For bulk batch pipelines, email [email protected] with your expected volume to discuss higher limits.
Yes. Pass webhook_url in your JSON request body and PixelAPI will POST the completed job result to your endpoint the moment processing finishes. This eliminates the polling loop for server-to-server integrations and serverless functions.
Yes, as long as the model photo is a clear front-facing image with the person fully visible at sufficient resolution. The API accepts any JPEG, PNG, or WebP up to 10 MB. All inputs are screened by an automated safety layer before processing — images that fail the check are rejected and credits are not charged.