Skip to main content
FLUX Outpainting extends an image naturally in any direction, filling new regions with contextually coherent content in a single call. Useful for aspect-ratio changes, banner generation, social media reformatting, or giving a composition more room to breathe.
Try it interactively and for free in our FLUX Outpainting demo.

Example output

Drag the slider to compare the input image padded onto the target canvas (left) with the outpainted result (right). No prompt was used — the model extended the scene on its own.

Endpoint

Submit an outpainting job:
POST https://api.bfl.ai/v1/flux-tools/outpainting-v1
x-key: $BFL_API_KEY
Poll for the result:
GET https://api.bfl.ai/v1/get_result?id=<TASK_ID>
x-key: $BFL_API_KEY

Quick start

The API uses an asynchronous workflow:
1

Submit an outpainting request

POST your input image (base64) and the target canvas dimensions to the endpoint. The model extends the existing scene naturally — no prompt is needed.
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"}

IMAGE_PATH = "/path/to/input.png"
WIDTH, HEIGHT = 1024, 1024
REFERENCE_OFFSET_X = 100   # None = center horizontally
REFERENCE_OFFSET_Y = 50    # None = center vertically

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

payload = {
    "input_image": image_b64,
    "width": WIDTH,
    "height": HEIGHT,
    "output_format": "png",
}

if REFERENCE_OFFSET_X is not None:
    payload["reference_offset_x"] = REFERENCE_OFFSET_X
if REFERENCE_OFFSET_Y is not None:
    payload["reference_offset_y"] = REFERENCE_OFFSET_Y

submit = requests.post(f"{BASE}/v1/flux-tools/outpainting-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"Outpainting failed with status: {status} | payload: {result}")

    time.sleep(1)

Request parameters

ParameterTypeRequiredDescription
input_imagebase64 stringYesReference image to expand
widthintegerYesTarget canvas width in pixels (>=64). width × height must not exceed 4 MP
heightintegerYesTarget canvas height in pixels (>=64). width × height must not exceed 4 MP
reference_offset_xintegerNoLeft offset (px) of the reference image’s top-left corner on the canvas. Negative values allowed. None = center horizontally
reference_offset_yintegerNoTop offset (px) of the reference image’s top-left corner on the canvas. Negative values allowed. None = center vertically
auto_cropbooleanNoIf true, crop the reference image to the canvas bounds when it extends beyond the edges. Defaults to false (out-of-bounds placements return 422)
modestringNoQuality/speed trade-off: high (default) or fast. See Choosing a mode
output_formatstringNopng (default) or jpeg
Maximum canvas size: 4 MP. The target canvas area (width × height) cannot exceed 4 megapixels (4,194,304 pixels). You’re free to choose any aspect ratio within that budget — for example 2048 × 2048, 2730 × 1536 (16:9), or 1024 × 4096 — as long as the two dimensions multiplied together stay at or below 4 MP. Requests above this limit return 422.

Image placement

reference_offset_x and reference_offset_y set the top-left corner of the reference image on the output canvas. Drag the reference below to see how the offsets relate to the canvas: You have two options for placing the reference image on the output canvas:
  • Centered (default) — provide the image, set width and height, and leave reference_offset_x / reference_offset_y as None. The image is centered automatically.
  • Custom position — set reference_offset_x and reference_offset_y to control exactly where the top-left corner of the reference image lands on the canvas. Negative values are allowed; if any part of the reference falls outside the canvas, either set auto_crop: true or the request will return 422.

Choosing a mode

The mode parameter trades quality for speed. Both modes accept the same request fields (input_image, width, height, reference_offset_x / reference_offset_y, auto_crop, prompt) and produce the same response format.
ModeSpeedBest for
high (default)SlowerThe highest-fidelity results — recommended whenever fine detail, prompt adherence, or consistency with complex content in the source image matters.
fastSignificantly fasterNaturally extending most scenes — landscapes, backgrounds, textures, and products. May produce lower fidelity in the extended region than high. Typically lower cost as well.
If you omit mode, the request runs in high mode.
payload = {
    "input_image": image_b64,
    "width": 1024,
    "height": 1024,
    "mode": "fast",          # opt into the faster path
    "output_format": "png",
}
Fast mode requirements. Fast mode encodes the reference and pads it in latent space, so a few extra constraints apply on top of the shared ones. Requests that violate them return 422:
  • input_image must be a base64-encoded image — image URLs are not supported in fast mode.
  • The placed reference must be at least 64 px per side and have an aspect ratio of at most 8:1.
  • The canvas (width × height) plus internal alignment padding must stay at or below 4 MP. A canvas right at the 4 MP limit may be rejected because of the added padding — reduce it slightly if so.
Any reference_offset_x / reference_offset_y, width, and height are otherwise accepted; you don’t need to pre-align them.

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.

Tips for best results

  • The model extends the existing scene naturally. The endpoint is tuned to continue the input image’s content, lighting, and composition on its own.
  • The model was trained on green, blue, and magenta fill colors and performs best with those internally — no caller action needed; the server handles fill colors automatically.
  • Keep total output dimensions reasonable. The canvas area (width × height) is capped at 4 MP, and very large canvases or extreme aspect ratios may reduce quality even within that limit.

Troubleshooting

  • 403 Forbidden — your API key is missing or your project doesn’t have access to this endpoint.
  • 422 / validation errors — check base64 encoding and that width / height are present, at least 64, and that their product (width × height) does not exceed 4 MP. The endpoint rejects unknown fields: use reference_offset_x / reference_offset_y (not the older bbox_x1 / bbox_y1).
  • 422 in fast mode specifically — fast mode adds extra geometry constraints (see Choosing a mode): pass a base64 image (not a URL), keep the placed reference ≥ 64 px per side and within an 8:1 aspect ratio, and leave headroom below 4 MP so internal alignment padding still fits. Switch to mode: "high" if your placement can’t satisfy these.
  • Visible seams — give the model more canvas room around the reference image.
For the full list of HTTP status codes and polling response types returned by the API, see the Errors reference.