Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.bfl.ml/llms.txt

Use this file to discover all available pages before exploring further.

FLUX VTO enables you and your customers to generate virtual try-on for any person on any garment! The endpoint is optimized for low latency, making it ideal for interactive applications like virtual fitting rooms and social media filters.
Try it interactively and for free in our BFL Shop Demo.
Make sure to read the prompting tips and reference image guidance below. They have a significant impact on the output quality.

Examples

A single garment shown as a packshot. Use this when you have an individual product shot.

The person of image 1, maintaining exactly their face and pose, wearing the olive green bomber jacket with 'Black Forest Labs' branding of image 2.

Prompting tips

  • Core prompt formula: The person of image 1, maintaining exactly their face and pose, wearing the {YOUR GARMENT DESCRIPTIONS} of image 2.
  • A good default is even a static prompt like The person of image 1, maintaining exactly their face and pose, wearing the garments of image 2.. But to get higher quality results, we recommend to add a concise description of the garments. Especially for complex garments, a detailed description can significantly improve the outcome.
    You can for instance specify the fit and category of the garment like for example:
    • the oversized tee
    • the cap with Keep FLUXing text
    • the 7/8 length pants.
  • When using another model shot as garment reference, only describe what should be tried on from that image and don’t specify in the prompt what should be kept from the model image.
    For instance, if the garment reference image also shows a model wearing pants, but you only want to try on the top, your prompt could be: The person of image 1, maintaining exactly their face and pose, wearing the green jacket of image 2.

Reference images

General guidance

  • Input images (both model and garment) up to 2 Megapixels are used as-is. Larger inputs are automatically downscaled to a ~1 Megapixels target while preserving aspect ratio.
  • For best results and latency, keep the model image and the garment image at around 1 Megapixels.
  • Some artifacts from existing clothing may be retained in the output. If you are consistently seeing this, you can try preprocessing the model image to get a more neutral base for the try-on. A neutral base could mean just wearing tight-fitting, plain clothing.
  • For the garment reference, clean, well-lit images with a clear view of the garment details work best. Both packshot and on-model references are supported, but packshot references with a plain background tend to produce the best results.

Designing the garment image

If you want to generate an image with more than one garment, merge them into a single canvas first. This reduces extra file handling overhead and optimizes for latency.
Four garments (jacket, cap, t-shirt, pants) arranged in a 2x2 grid as a single garment reference image

Endpoint

Submit a try-on job:
curl -X POST https://api.bfl.ai/v1/flux-tools/vto-v1 \
  -H "x-key: $BFL_API_KEY"
Poll for the result:
curl https://api.bfl.ai/v1/get_result?id=<TASK_ID> \
  -H "x-key: $BFL_API_KEY"

Regional endpoints

To reduce latency, you can pin requests to a specific region by swapping the host:
  • https://api.eu.bfl.ai/v1/flux-tools/vto-v1 — Europe
  • https://api.us.bfl.ai/v1/flux-tools/vto-v1 — US
Pick the region closest to your traffic, this can make a difference of up to 1 second in latency. The polling_url returned in the submit response will match the region you submitted to — always poll the URL returned in the response rather than rewriting the host. Follow the regional endpoints guide for more information on the regional endpoints and how to use them.

Quick start

The API uses an asynchronous workflow:
1

Submit a VTO request

POST a person image and one or more garment images, together with a styling prompt, to the model endpoint.
2

Poll for the result

Use the returned polling_url to check status until the image is ready.
#!/usr/bin/env python3
import base64
import os
import time
import requests

API_KEY = os.environ["BFL_API_KEY"]
BASE = "https://api.bfl.ai"
HEADERS = {"accept": "application/json", "x-key": API_KEY, "Content-Type": "application/json"}

PROMPT = "The person of image 1, maintaining exactly their face and pose, wearing the white t-shirt of image 2."
PERSON_PATH = "/path/to/person.png"
GARMENT_PATH = "/path/to/garment_top.png"

with open(PERSON_PATH, "rb") as f:
    person_b64 = base64.b64encode(f.read()).decode()

with open(GARMENT_PATH, "rb") as f:
    garment_b64 = base64.b64encode(f.read()).decode()

payload = {
    "prompt": PROMPT,
    "person": person_b64,
    "garment": garment_b64,
    "output_format": "webp",
}

submit = requests.post(f"{BASE}/v1/flux-tools/vto-v1", headers=HEADERS, json=payload)
submit.raise_for_status()
meta = submit.json()

task_id = meta["id"]
poll_url = meta.get("polling_url", f"{BASE}/v1/get_result?id={task_id}")

while True:
    r = requests.get(poll_url, headers={"accept": "application/json", "x-key": API_KEY})
    r.raise_for_status()
    result = r.json()

    status = result.get("status")
    if status == "Ready":
        print("Result URL:", result["result"]["sample"])
        break
    if status in {"Error", "Request Moderated", "Content Moderated", "Task not found"}:
        raise RuntimeError(f"VTO failed with status: {status} | payload: {result}")

    time.sleep(1)

Request parameters

Use person + garment as the minimum payload.
ParameterTypeRequiredDescription
promptstringYesNatural-language styling instruction
personstringYesPerson image — URL or base64 (mapped to input_image)
garmentstringYesGarment reference — URL or base64 (mapped to input_image_2)
seedintegerNoFor reproducibility
safety_toleranceintegerNo0–5, defaults to 2. Moderation strictness for input and output
output_formatstringNojpeg (default), png, webp
webhook_urlURLNoAsync callback
webhook_secretstringNoSignature secret

Response format

Initial response

{
  "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "polling_url": "https://api.bfl.ai/v1/get_result?id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
Always poll the URL returned in the response.

Polling response (success)

{
  "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  "status": "Ready",
  "result": {
    "sample": "https://delivery.bfl.ai/..."
  }
}
When status is "Ready", use result.sample.
Signed delivery URLs are only valid for 10 minutes. Retrieve your result within this timeframe.
For the full list of HTTP status codes and polling response types returned by the API, see the Errors reference.