Search

Search HiAPI models, tools, and resources.

Back to blog
Tutorial

How to Use the FLUX.1 Fill Pro API: Mask Inpainting with curl and Python

hiapiflux-1-fill-proinpaintingimage-editing

flux-1-fill-pro is hiapi's mask-based inpainting model: you send a source image, a black-and-white mask and a prompt, and only the white area is repainted. This guide gives a working curl and Python request, the async flow, and what one real run showed about the mask boundary and output size. You need an API key from the dashboard.

Request shape

The model runs on the unified task API. Create a task with POST https://api.hiapi.ai/v1/tasks, poll GET /v1/tasks/<taskId>, and read data.output[0].url. The inputs below come from the model page and the API docs:

FieldTypeNotes
input.imageURL, requiredSource image. JPEG, PNG, GIF or WebP.
input.maskURL, requiredBlack keeps the source, white is repainted. Must match the source dimensions.
input.promptstring, requiredDescribe the new content inside the white area. Up to 4,000 characters.
input.stepsint, 15–50Default 50.
input.guidancenumber, 1.5–100Default 60.
input.seedintFixed seed with identical inputs gives a consistent result.
input.output_formatjpg | pngDefault jpg.
input.prompt_upsamplingboolDefault false. Leave it off to keep your exact wording.

Both image and mask are URLs, not base64 or file uploads. Host them somewhere the API can fetch over http(s).

Minimal curl request

curl -s https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-1-fill-pro",
    "input": {
      "image": "https://dev-static.hiapi.ai/model-onboarding/flux-1-fill-pro/2026/10/19/2026/10/19/1792418738578-4e5072a121d7018f-source.jpg",
      "mask": "https://dev-static.hiapi.ai/model-onboarding/flux-1-fill-pro/2026/10/19/2026/10/19/1792418739459-82bb18075f29c864-mask.png",
      "prompt": "A large framed oil landscape of a misty mountain lake at dawn, thin black frame, hanging flat on the wall; keep the sofa, floor and lighting unchanged.",
      "steps": 30,
      "guidance": 60,
      "seed": 42,
      "output_format": "png"
    }
  }'

The response is {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}. Poll that ID until data.status is success or fail.

Python: create, poll, download

import os, time, requests

API = "https://api.hiapi.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_KEY']}"}

def inpaint(image_url, mask_url, prompt, **opts):
    body = {"model": "flux-1-fill-pro",
            "input": {"image": image_url, "mask": mask_url, "prompt": prompt, **opts}}
    r = requests.post(f"{API}/v1/tasks", headers=HEADERS, json=body, timeout=30)
    r.raise_for_status()
    task_id = r.json()["data"]["taskId"]

    while True:
        try:
            d = requests.get(f"{API}/v1/tasks/{task_id}", headers=HEADERS, timeout=20).json()["data"]
        except requests.RequestException:
            time.sleep(5)          # transient network error: poll the same taskId again
            continue
        if d["status"] == "success":
            return d["output"][0]["url"]
        if d["status"] == "fail":
            raise RuntimeError(d.get("error", d))
        time.sleep(5)

url = inpaint(
    "https://example.com/room.jpg",
    "https://example.com/room-mask.png",
    "A framed landscape painting, thin black frame; keep the room unchanged.",
    steps=30, seed=42, output_format="png",
)
open("out.png", "wb").write(requests.get(url, timeout=60).content)

Download the result right away. The output URL carries an expireAt and the file is temporary storage, so do not store the link as the permanent address.

Production notes

  • Poll or callback. For batch jobs, add "callback": {"url": "https://your-domain.com/hiapi/callback", "when": "final"} to the task body, and use the task ID to deduplicate notifications. Keep polling as a fallback.
  • Retry the poll, not the create. A new POST creates and bills a new task. If one poll request errors out, poll the same taskId again.
  • Keep the mask next to the source. The mask has to match the source dimensions exactly, so generate it from the same file (polygon tool, segmentation output) instead of resizing a screenshot.
  • Fix the seed while tuning. Use one seed and change only steps or guidance, so each difference comes from that parameter.

Per-image cost is on the pricing page, so check it before running large catalogs.

What one real run showed

I ran the curl request above once against the page's own example room photo (1600×900) and its rectangular mask (white box at x 840–1240, y 160–580). Settings were steps: 30, guidance: 60, seed: 42, output_format: png.

  • Timing. The task went handling for about 25 s, then archiving, and reached success in about 38 s end to end.
  • Output size differs from the source. The returned PNG was 1440×810, not 1600×900. The aspect ratio matched, but the pixel size did not. If you composite the result back onto the original, resize one of them first and do not assume 1:1.
  • Outside the mask stays put. After scaling the source to 1440×810 and diffing against the output, 81% of pixels inside the white box changed by more than 8 levels (0–255), while only 0.03% of the pixels outside it did. More than 12 px from the mask edge, the largest difference was 11 levels. The sofa, cushions, plant, floor and window light were not repainted.
  • Prompt scope. The prompt described only the painting and what to preserve, and the result is a framed mountain-lake scene that fills the white box.
  • A bad URL fails on the poll, not on create. A separate request with image and mask set to a non-URL string returned 200 and a taskId, then the task ended with status: fail and error.code: TASK_FAILED about 3 seconds later. Your POST succeeding does not mean your inputs were valid, so always check the terminal state.

Not tested: mismatched mask and source dimensions, masks with grey (soft-edge) values, alpha-channel masks, and guidance or steps extremes. The docs say the mask must match the source size, and I only tested a hard two-value rectangle. I did not run more than one seed, so I cannot say how much the fill varies from run to run.

When to pick Fill Pro

Use it when the edit has to stop at a hard boundary you control, such as a product label, a wall line or a garment seam. For edits you describe in words with no mask, use a prompt-only model. The image inpainting and object removal guide compares those. To erase something from a mask without writing a prompt, see the Bria Eraser guide.

FAQ

Are both image and mask required?

Yes. The current docs list image, mask and prompt as required.

Which color does the model repaint?

White. Black pixels keep the source.

Does the mask need to be the same size as the source?

The docs say so. I used a matching pair in my run, and I did not test a mismatched one.

What does the output look like in size?

In my run a 1600×900 source returned a 1440×810 PNG with the same aspect ratio.

Generate it with HiAPI

Choose a model, enter your prompt, and see the result.

HiAPI Blog

Related articles

HiAPI

Generate it with HiAPI

Start generating