FLUX.2 has no editing endpoint of its own. Editing is the same POST you already send for text to image, with one or more input_image fields added, and that one design choice decides how the rest of the client gets built.

Every endpoint, field and limit below comes from the official Black Forest Labs documentation. Where the vendor has published nothing, this page says so instead of filling the gap.

How the FLUX.2 editing endpoint works

The three-step job lifecycle

An edit is a job, not a response with a picture inside it. You POST to https://api.bfl.ai/v1/flux-2-pro-preview, the endpoint the official editing page uses, or to the pinned flux-2-pro when you need the same weights to answer the same prompt twice. The reply carries an id and a polling_url; GET that URL with the same key header, and the image appears as result.sample once status reads Ready.

The signed URL expires after ten minutes, so the download belongs in the same run as the polling loop.

Authentication is one x-key header, not a bearer token. The getting started guide covers creating that key.

A multi-reference request you can run

Field names that matter

prompt is the only required field. input_image holds the first reference, input_image_2 the second, and the numbering runs to input_image_8. The API reference for FLUX.2 [pro] documents exactly those eight; the [klein] 4B reference stops at input_image_4 and describes the model as “like Pro but max 4 images”.

width and height are integers with a documented minimum of 64 each. seed, safety_tolerance from 0 to 5, output_format as jpeg, png or webp, webhook_url and webhook_secret are optional, and user takes an opaque identifier of 1 to 256 characters.

One absence is worth planning around: there is no negative_prompt field. Whatever you want kept out of the frame has to be written as a positive description of the frame you do want.

# Requires curl and jq. BFL_API_KEY comes from dashboard.bfl.ai.
API_BASE="https://api.bfl.ai/v1"
MODEL="flux-2-pro-preview"

response=$(curl -s -X POST "${API_BASE}/${MODEL}" \
  -H "x-key: ${BFL_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Keep the room from image 1, place the chair from image 2 on the rug from image 3, keep the chair proportions and the rug pattern, warm afternoon light.",
    "input_image": "https://example.com/room.jpg",
    "input_image_2": "https://example.com/chair.jpg",
    "input_image_3": "https://example.com/rug.jpg",
    "width": 1024,
    "height": 1024,
    "output_format": "png"
  }')

polling_url=$(echo "${response}" | jq -r .polling_url)

while true; do
  sleep 0.5
  result=$(curl -s "${polling_url}" \
    -H "accept: application/json" \
    -H "x-key: ${BFL_API_KEY}")

  status=$(echo "${result}" | jq -r .status)
  echo "Status: ${status}"

  if [ "${status}" = "Ready" ]; then
    curl -sL -o edit.png "$(echo "${result}" | jq -r .result.sample)"
    break
  elif [ "${status}" = "Error" ] || [ "${status}" = "Failed" ]; then
    echo "Generation failed: ${result}"
    break
  fi
done

Referring to images inside the prompt

The multi-reference guide states the rule in one line: describe the role of each image so the model knows what to pull from where. Its recommended phrasing is as literal as Change image 1 to match the style of image 2.

Field order is therefore part of the prompt. A sentence about “the wood from image 5” only works if the wood was sent fifth.

The guide also lists phrasings to avoid: Make it better, Improve the lighting, Make it more professional, Fix the image. Each one asks the model to guess your target state.

A left to right editing pipeline: one input image tile, three control sliders and two output image tiles joined by arrows.
Create a house for the chickens from image 1 using materials from images 2, 3, 4, and 5. Use the wood from image 5 for the base, the materials from images 2 and 4 for the walls and floor, and the material from image 3 for a small pillow nest. Place the chickens from image 1 in their new home, sitting on the pillow nest. Next to them, include the eggs from image 6. Apply the style of image 1 to the entire new scene.

That prompt is the one published on the official editing page. Every reference gets an index, a material and a destination, which is the shape a production edit prompt should have.

A Python client that polls and saves

In a service, submit and poll belong in one function so the ten-minute window can never be missed.

import os
import time

import requests

API_BASE = "https://api.bfl.ai/v1"
MODEL = "flux-2-pro-preview"
HEADERS = {
    "accept": "application/json",
    "x-key": os.environ["BFL_API_KEY"],
    "Content-Type": "application/json",
}


def edit(prompt: str, references: list[str], width: int = 1024, height: int = 1024) -> bytes:
    payload = {"prompt": prompt, "width": width, "height": height}
    # input_image, input_image_2, ... input_image_8
    for index, url in enumerate(references[:8], start=1):
        key = "input_image" if index == 1 else f"input_image_{index}"
        payload[key] = url

    response = requests.post(f"{API_BASE}/{MODEL}", headers=HEADERS, json=payload, timeout=30)
    response.raise_for_status()
    polling_url = response.json()["polling_url"]

    for _ in range(120):
        time.sleep(0.5)
        result = requests.get(polling_url, headers=HEADERS, timeout=30).json()
        status = result["status"]
        if status == "Ready":
            sample = requests.get(result["result"]["sample"], timeout=60)
            return sample.content
        if status in ("Error", "Failed"):
            raise RuntimeError(result)
    raise TimeoutError("no result after 120 polls")


with open("edit.png", "wb") as handle:
    handle.write(
        edit(
            "Keep the room from image 1, place the chair from image 2 on the rug from image 3, warm afternoon light.",
            [
                "https://example.com/room.jpg",
                "https://example.com/chair.jpg",
                "https://example.com/rug.jpg",
            ],
        )
    )

The reference list is sliced to eight before the fields are built, so an over-long list degrades instead of failing validation. The download happens inside the loop, while the signed URL is still alive.

Limits the API reference documents

Reference count is not one number. The overview gives [klein] four, [max], [pro] and [flex] eight through the API and ten in the playground, and [dev] a recommended maximum of six. On [pro] the count then bends with output size, because the 9 MP budget covers input plus output:

Output size on [pro]Reference images the 9 MP budget allows
1 MPup to 8
2 MPup to 7
3 MPup to 6

Prompt upsampling differs by tier too. [pro] and [max] rewrite your prompt by default and expose disable_pup to stop it; [klein] has no upsampling, which is why the overview tells you to write detailed prompts there. Editing rates are covered in the FLUX.2 API pricing article.

Poll states are documented on the Get Result page: Task not found, Pending, Reasoning, Generating, Request Moderated, Content Moderated, Ready and Error. A moderation state is not a payload bug, and resending the identical request will not clear it.

For prompt craft rather than plumbing, the FLUX.2 prompt guide covers structure and hex colour control, and the Nano Banana Pro comparison is where to look when a different model is competing for the same edit.

What the official pages leave out

No success rate, median latency or per-country availability figure appears on the pages read for this article. There is also no free API allowance: the playground needs no signup and no card, but it is a demo, not a quota.

File handling is unstated as well. The reference calls each field the path to an input image and the official example passes a public URL; no file-size ceiling, MIME list or retention policy is published.

Frequently asked questions

Is there a dedicated FLUX.2 image editing endpoint? No. Editing uses the same /v1/flux-2-pro-preview or /v1/flux-2-pro endpoint as generation, with input_image fields added to the body.

How many reference images can one request carry? Four on [klein], eight through the API on [max], [pro] and [flex], ten in the playground, six on [dev]. On [pro] the 9 MP input-plus-output budget lowers that as output grows.

Can I pass a negative prompt? There is no negative_prompt field in the documented body. Describe the target state instead.

Do I have to poll? Yes. The submit response returns a polling_url, and result.sample exists only once the status reads Ready.

How long is the result link valid? Ten minutes. Download inside the same run as the polling loop.