VirtuFit

Documentation

VirtuFit API reference

Use the virtual try-on API to generate images of a person wearing your garment(s). Authenticate with an API key and send a person photo plus one or more garment images.

Base URL

https://virtufit-seven.vercel.app

All endpoints are relative to this base. Production: https://virtufit.xyz. Local dev: http://localhost:3000.

Authentication

Send your API key in the X-API-Key header. Create and manage keys from the Dashboard.

X-API-Key: your_api_key_here

POST /api/v1/generate

Generate virtual try-on image(s): one person photo + one or more garment images. Each garment produces one output image. Credits are deducted per run (see Credits & tiers).

Request

  • Content-Type: multipart/form-data

Parameters

FieldTypeRequiredDescription
person_imageFileYes*Person photo (JPEG, PNG, WebP; max 10MB). *Or use person_image_url.
person_image_urlStringNoURL of person image instead of uploading a file.
garment_imageFile(s)Yes*One or more garment images (1–5 total). *Or use garment_urls.
garment_urlsStringNoComma-separated URLs of garment images (max 5).
tierStringNoOne of: nano, basic, pro. Default: basic.
swap_targetStringNoWhat to swap: full_outfit, top, bottom, dress, jacket, watch, glasses, shoes, hat, bag, jewelry, other. Default: full_outfit.
garment_descriptionStringNoOptional text description of the garment (e.g. "white linen shirt") to improve results.
webhook_urlStringNoHTTPS URL to POST completion/failure payload (retries with backoff).
webhook_secretStringNoOptional secret to sign webhook body (X-VirtuFit-Signature: HMAC-SHA256).

Async response (202 Accepted)

When the job queue is available, the API returns 202 Accepted immediately. Poll status_url or provide webhook_url for the result.

{
  "accepted": true,
  "job_id": "uuid",
  "status": "queued",
  "status_url": "https://virtufit-seven.vercel.app/api/v1/jobs/<job_id>",
  "message": "Generation queued. Poll status_url or provide webhook_url for callback.",
  "estimated_seconds": 15,
  "credits_reserved": false
}

Success response (200, sync fallback)

{
  "success": true,
  "job_id": "abc123",
  "output_url": "https://...",
  "output_urls": ["https://...", "https://..."],
  "tier": "basic",
  "credits_used": 2,
  "credits_remaining": 48,
  "processing_time_ms": 12000
}

Response fields

  • success — true on success (200)
  • job_id — unique job identifier
  • output_url — first result image URL
  • output_urls — array of all result image URLs (one per garment)
  • tier — tier used
  • credits_used — credits deducted
  • credits_remaining — balance after request
  • processing_time_ms — total time in milliseconds

Async flow & job status

1. POST /api/v1/generate → returns 202 + job_id and status_url. 2. Poll GET /api/v1/jobs/:jobId every 2–5 seconds (same X-API-Key or session), or provide webhook_url to receive the result automatically. 3. When status is completed, use output_urls.

Best practice: use webhook_url for server-side integrations (more reliable than polling). Poll no faster than every 2 seconds. Job status is available for 24 hours.

Rate limits

Multiple garments in one request are processed sequentially with a short delay between runs. Avoid sending many concurrent requests; typical limits are on the order of a few requests per minute per account. For high volume, space out requests or contact support.

Example requests

Replace YOUR_API_KEY and file paths as needed.

cURL

curl -X POST "https://virtufit-seven.vercel.app/api/v1/generate" \
  -H "X-API-Key: YOUR_API_KEY" \
  -F "person_image=@/path/to/photo.jpg" \
  -F "garment_image=@/path/to/garment.jpg" \
  -F "tier=basic" \
  -F "swap_target=full_outfit"

JavaScript (fetch)

const form = new FormData();
form.append('person_image', personFile);
form.append('garment_image', garmentFile);
form.append('tier', 'basic');
form.append('swap_target', 'full_outfit');

const res = await fetch('https://virtufit-seven.vercel.app/api/v1/generate', {
  method: 'POST',
  headers: { 'X-API-Key': 'YOUR_API_KEY' },
  body: form,
});
const data = await res.json();

Python

import requests

url = "https://virtufit-seven.vercel.app/api/v1/generate"
headers = {"X-API-Key": "YOUR_API_KEY"}
files = {
    "person_image": open("/path/to/photo.jpg", "rb"),
    "garment_image": open("/path/to/garment.jpg", "rb"),
}
data = {"tier": "basic", "swap_target": "full_outfit"}

r = requests.post(url, headers=headers, files=files, data=data)
print(r.json())

PHP

$ch = curl_init('https://virtufit-seven.vercel.app/api/v1/generate');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['X-API-Key: YOUR_API_KEY'],
    CURLOPT_POSTFIELDS => [
        'person_image' => new CURLFile('/path/to/photo.jpg'),
        'garment_image' => new CURLFile('/path/to/garment.jpg'),
        'tier' => 'basic',
        'swap_target' => 'full_outfit',
    ],
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$data = json_decode($response, true);

Error codes

401Invalid or missing API key
402Insufficient credits (response includes required and balance)
413File too large (max 10MB per file)
415Unsupported file type (use JPEG, PNG, or WebP)
422Validation failed (missing/invalid fields; see details in body)
500Generation failed or upload failed (retryable)
504Generation timed out (retryable)

Credits & tiers

Each generation run consumes credits based on tier. One garment = one run. Multiple garments in a single request are charged per garment.

  • nano — 1 credit per run (lower resolution)
  • basic — 1 credit per run (1K)
  • pro — 3 credits per run (2K)

Example: 1 person + 3 garments with tier=basic = 3 credits. With tier=pro = 9 credits.

Swap targets

Use swap_target to tell the model what to replace: full outfit, only the top, only a watch, glasses, shoes, etc. This improves accuracy.

full_outfittopbottomdressjacketwatchglassesshoeshatbagjewelryother

Webhook

If you pass webhook_url, we POST JSON when the job completes or fails. We retry up to 3 times with exponential backoff (5s, 25s, 125s). Optional webhook_secret signs the body (header X-VirtuFit-Signature: HMAC-SHA256).

Success payload

{
  "event": "tryon.completed",
  "job_id": "...",
  "status": "completed",
  "output_urls": ["https://..."],
  "output_url": "https://...",
  "tier": "basic",
  "credits_used": 1,
  "credits_remaining": 148,
  "processing_ms": 14200,
  "timestamp": "2026-03-15T..."
}

Failure payload

{
  "event": "tryon.failed",
  "job_id": "...",
  "status": "failed",
  "error": "Replicate API error: ...",
  "credits_used": 0,
  "attempts": 3,
  "timestamp": "2026-03-15T..."
}

Live API playground

Logged-in users can test the API here. Paste your API key, upload images, and send a real request.