HiAPI
  • Models
  • Pricing
Search

Search HiAPI models, tools, and resources.

  • Models
  • Pricing
HiAPI

One API, All AI Models

Generate images, video, and audio with leading models through one production-ready API.

Get a free API key

AI Image API

  • All image models
  • GPT Image 2
  • Nano Banana 2
  • Seedream 5.0 Pro
  • Qwen Image 2.0 Pro
  • FLUX 1.1 Pro

AI Video API

  • All video models
  • Seedance 2.5
  • FLUX.3 Video
  • Seedance 2.0
  • Veo 3.1
  • Kling 3.0 Omni

AI Audio API

  • All audio models
  • MiniMax Music 2.6
  • MiniMax Music 1.5
  • ElevenLabs v3
  • Text to music
  • Text to speech

Product

  • Model marketplace
  • Playground
  • Pricing
  • Image API Cost Calculator
  • Free GPT Image 2 Generator
  • Free Nano Banana Image Generator
  • Outfit Preview
  • Product Photo Lab

Developers

  • Documentation
  • API Reference
  • Agent Skills
  • LLM integration index
  • Blog

Company

  • About
  • Contact support
  • Terms of Service
  • Privacy Policy

© 2026 hiapi. All rights reserved.

Open source on GitHubPython SDK on PyPI
  • What you'll build, and what you need
  • Minimal runnable example (curl)
  • Full Python workflow: submit → poll → download
  • Writing removal prompts that actually work
  • Switching models: same lifecycle, different input
  • Production notes
  • Related reading
  • FAQ
TutorialJul 12, 2026

Image Inpainting and Object Removal via API: Image-to-Image Models on hiapi

hiapiTutorialImage GenerationImage EditingAPI

Latest models

Explore models

Contents
  • What you'll build, and what you need
  • Minimal runnable example (curl)
  • Full Python workflow: submit → poll → download
  • Writing removal prompts that actually work
  • Switching models: same lifecycle, different input
  • Production notes
  • Related reading
  • FAQ

Generate it with HiAPI

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

HiAPI Blog

Related articles

HiAPI

Generate it with HiAPI

If you are searching for an image inpainting API, one fact changes how you write your code: the current generation of image-to-image models on hiapi does not take a mask. All four editing endpoints — flux-2/image-to-image, seedream-4.5/image-to-image, seedream-5.0-pro/image-to-image, and gpt-image-2/image-to-image — are instruction-based. You describe the edit in plain language ("remove the white van on the right, reconstruct the storefront behind it") and the model localizes the change itself. The schemas are strict: send a mask_url and the API answers 400 INVALID_REQUEST with additional properties 'mask_url' not allowed.

Every endpoint shares the same async lifecycle — POST /v1/tasks to submit, poll GET /v1/tasks/<id> (or receive a callback), then download output[0].url. What differs is the input schema, and each one below was validated against the live API:

Model idRequired input fieldsaspect_ratio valuesOutput size control
flux-2/image-to-imageprompt, image_urls, aspect_ratio, resolution1:1, 4:3, 3:4, 16:9, 9:16, 3:2, 2:3, autoresolution: 1K, 2K
seedream-4.5/image-to-imageprompt, image_urls, aspect_ratio, resolution1:1, 4:3, 3:4, 16:9, 9:16, 2:3, 3:2, 21:9resolution: 2K, 4K
seedream-5.0-pro/image-to-imageprompt, image_urls, aspect_ratio, quality1:1, 4:3, 3:4, 16:9, 9:16, 2:3, 3:2quality: basic, high
gpt-image-2/image-to-imageprompt, input_urls— (decided by the model)— (decided by the model)

Two gotchas hide in that table. First, gpt-image-2/image-to-image names its image field input_urls, not image_urls. Second, only flux-2/image-to-image accepts aspect_ratio: "auto", which preserves the source image's framing — exactly what you want for object removal, so it is the default model in this guide.

What you'll build, and what you need

Goal: a small Python function that takes a source image URL plus an edit instruction, and returns the edited image bytes — usable for object removal, background cleanup, filling gaps, and local rewrites.

You need two things:

  1. A hiapi API key — grab it from your hiapi dashboard. It looks like sk-... and goes in the Authorization: Bearer header.
  2. Your source image at a publicly reachable URL. The models fetch it server-side; local file paths and private URLs won't work.

Minimal runnable example (curl)

Submit an object-removal edit with flux-2:

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2/image-to-image",
    "input": {
      "prompt": "Remove the white delivery van parked on the right side of the street. Reconstruct the storefront and sidewalk that were behind it. Keep the lighting, colors, and everything else unchanged.",
      "image_urls": ["https://your-cdn.example.com/street.jpg"],
      "aspect_ratio": "auto",
      "resolution": "2K"
    }
  }'

A successful submit returns a task id:

{"code": 200, "data": {"taskId": "task_abc123"}}

Then poll until the task reaches a terminal status (success or fail):

curl https://api.hiapi.ai/v1/tasks/task_abc123 \
  -H "Authorization: Bearer sk-<your-key>"

On success, the edited image is at data.output[0].url. That URL is temporary (the response includes an expireAt) — download the bytes immediately and store them yourself; never hotlink it.

Full Python workflow: submit → poll → download

import os
import time

import requests

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


def edit_image(model: str, input_payload: dict, timeout_s: int = 300) -> bytes:
    """Submit an image-to-image task, poll to a terminal state, return image bytes."""
    # 1. Submit
    resp = requests.post(
        f"{API}/tasks",
        json={"model": model, "input": input_payload},
        headers=HEADERS,
        timeout=60,
    )
    resp.raise_for_status()
    task_id = resp.json()["data"]["taskId"]

    # 2. Poll until terminal status: "success" or "fail"
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        task = requests.get(
            f"{API}/tasks/{task_id}", headers=HEADERS, timeout=30
        ).json()["data"]

        if task["status"] == "success":
            # 3. Output URL expires — download right away
            url = task["output"][0]["url"]
            return requests.get(url, timeout=120).content

        if task["status"] == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task {task_id} failed: {err.get('code')} {err.get('message')}")

        time.sleep(5)

    raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")


image_bytes = edit_image(
    "flux-2/image-to-image",
    {
        "prompt": (
            "Remove the white delivery van parked on the right side of the street. "
            "Reconstruct the storefront and sidewalk that were behind it. "
            "Keep the lighting, colors, and everything else unchanged."
        ),
        "image_urls": ["https://your-cdn.example.com/street.jpg"],
        "aspect_ratio": "auto",
        "resolution": "2K",
    },
)

with open("street-clean.png", "wb") as f:
    f.write(image_bytes)

Run it with HIAPI_API_KEY=sk-... python edit.py. The only dependency is requests.

Writing removal prompts that actually work

Since there is no mask, the prompt is your mask. The pattern that holds up across all four models has three parts:

  1. Name the target precisely, with its location. "The white delivery van parked on the right side" beats "the van".
  2. Say what fills the gap. Models reconstruct better when told what should be there: "reconstruct the storefront and sidewalk behind it".
  3. Pin everything else. End with "keep the lighting, colors, and everything else unchanged" so the model doesn't restyle the whole frame.

The same pattern covers the neighboring inpainting jobs:

  • Erase + fill: "Remove the power lines crossing the sky. Fill with clear sky matching the existing gradient. Keep everything else unchanged."
  • Replace: "Replace the paper coffee cup on the table with a white ceramic mug. Match the scene's lighting and shadows. Keep everything else unchanged."
  • Repair / fill a damaged region: "The bottom-left corner of this scanned photo is torn and blank. Reconstruct the missing grass and path so it blends seamlessly. Do not alter the rest of the photo."
  • Batch cleanup in one pass: "Remove the trash bin near the bench and the two traffic cones on the road. Fill each area with a natural continuation of the background. Keep everything else unchanged."

Each call returns one output image, so for heavy cleanup you can also chain edits: run one removal, download the result, re-host it, and feed that URL into the next call. (Re-hosting matters — output URLs expire, so don't pass them directly as the next task's input.)

Switching models: same lifecycle, different input

The edit_image function above works unchanged for the other three endpoints — only the payload differs:

# Seedream 5.0 Pro: quality tiers instead of resolution, up to 10 reference images
edit_image("seedream-5.0-pro/image-to-image", {
    "prompt": "Remove the tourists from the plaza. Extend the paving stones. Keep everything else unchanged.",
    "image_urls": ["https://your-cdn.example.com/plaza.jpg"],
    "aspect_ratio": "3:2",
    "quality": "high",          # "basic" | "high" — this model has no "resolution" field
})

# Seedream 4.5: when you need 4K output
edit_image("seedream-4.5/image-to-image", {
    "prompt": "Remove the scaffolding from the building facade. Reconstruct the brickwork behind it. Keep everything else unchanged.",
    "image_urls": ["https://your-cdn.example.com/facade.jpg"],
    "aspect_ratio": "3:2",
    "resolution": "4K",         # "2K" | "4K" on this model (no "1K")
})

# GPT Image 2: simplest schema — note the field is input_urls
edit_image("gpt-image-2/image-to-image", {
    "prompt": "Remove the person walking through the frame on the left. Fill with the beach background. Keep everything else unchanged.",
    "input_urls": ["https://your-cdn.example.com/beach.jpg"],
})

These schemas are strict — unknown fields are rejected rather than ignored. That is a feature for debugging: a typo like image_url (singular) fails loudly at submit time with a per-field error message instead of silently producing a wrong result. But it also means you should not blind-copy an input payload from one model to another: sending flux-2's resolution to seedream-5.0-pro/image-to-image is a guaranteed 400.

Production notes

Callbacks instead of polling. For anything beyond a script, pass a callback at submit time — hiapi POSTs the task result to your URL once, when it reaches success or fail:

{
  "model": "flux-2/image-to-image",
  "input": { "...": "..." },
  "callback": { "url": "https://yourapp.com/hooks/hiapi", "when": "final" }
}

Polling is fine for CLIs and batch jobs (3–5 s interval is plenty); callbacks are better for user-facing apps and serverless backends where you don't want a worker occupying a slot just to wait. In your callback handler, download the output file immediately — the URL will have expired by the time a user clicks it later.

Persist the taskId before you poll. Submitting is the billable event. If your process crashes after submit, a naive retry re-submits and pays twice. Store the taskId (and your own request id) as soon as the submit response arrives, and on restart resume polling instead of re-creating the task.

Error handling. The two errors you'll actually see:

  • 401 permission_denied — the key is missing, malformed, or not allowed to use this model. Check the Authorization: Bearer sk-... header and the key's permissions in the dashboard.
  • 400 INVALID_REQUEST — the input failed schema validation. The message lists every failing field at once (e.g. resolution: value must be one of '1K', '2K'), so you can fix a payload in one iteration.

A fail status after submit (rather than an HTTP error at submit) usually means the source image URL wasn't fetchable or the content was rejected — the task's error.code and error.message say which.

Related reading

  • flux-2/image-to-image model page — parameters and interactive playground
  • seedream-4.5/image-to-image model page
  • seedream-5.0-pro/image-to-image model page
  • gpt-image-2/image-to-image model page
  • hiapi API docs — full task API reference
  • Pricing — per-image cost for every model and tier

FAQ

Does the hiapi inpainting API support masks? No. All four image-to-image endpoints reject mask fields (400: additional properties 'mask_url' not allowed). Precision comes from prompt specificity instead: name the object, its location, what replaces it, and pin the rest of the image. In practice this removes an entire step from your pipeline — no mask drawing UI, no segmentation model.

Which model is best for object removal? Start with flux-2/image-to-image: it is the only endpoint with aspect_ratio: "auto", so the output keeps your source framing. Use seedream-4.5/image-to-image when you need 4K output, seedream-5.0-pro/image-to-image when the edit needs multiple reference images (up to 10), and gpt-image-2/image-to-image when you want the simplest possible payload. Per-image prices differ by model and tier — compare them on the pricing page.

Can I remove several objects in one API call? Yes — list them in one prompt ("remove the trash bin and the two traffic cones..."). Each call produces one output image. For iterative cleanup, chain calls: download each result, re-host it on your own storage, and use that URL as the next call's input. Don't feed a task's output URL directly into the next task — those URLs expire.

How long does an inpainting task take? Typically from a few seconds up to about a minute, depending on model and output size — higher resolutions and quality tiers take longer. Poll every 3–5 seconds, or skip polling entirely with callback: {"url": ..., "when": "final"}.

Why does my request fail with a 400 before any image is generated? The task API validates input against a strict per-model schema at submit time. Common causes: using image_urls with gpt-image-2/image-to-image (it wants input_urls), sending resolution to seedream-5.0-pro/image-to-image (it uses quality), an aspect ratio outside the model's allowed list, or a prompt shorter than 3 characters. The error message names each offending field, so fixes are usually one-line.

Can I use inpainting output commercially? Generated output follows your plan's usage terms. Make sure you hold the rights to the source images you edit — removing objects from photos you don't own doesn't change the underlying copyright.

Latest models

View all models
  • GPT Image 2From $0.030/image
  • Nano Banana 2From $0.051/image
  • Seedream 5.0 ProFrom $0.050/image
  • Seedance 2.5From $0.231/s

Explore models

TextImageVideoAudio
Back to blog
GPT Image 2From $0.030/image
Nano Banana 2From $0.051/image
Seedream 5.0 ProFrom $0.050/image
Seedance 2.5From $0.231/s
View all models
TextChat and reasoning
ImageGenerate and edit
VideoText and image to video
AudioSpeech and music
Start generating
View model pricing
View all articles
How to Use the flux-3 API for Text-to-Video, Audio, and Continuation

How to Use the flux-3 API for Text-to-Video, Audio, and Continuation

minimax-music-3 API: curl & Python Guide

minimax-music-3 API: curl & Python Guide

How to use grok-imagine-image-2.0/image-to-image via the hiapi API: curl, Python, and a working request

How to use grok-imagine-image-2.0/image-to-image via the hiapi API: curl, Python, and a working request

How to Use grok-imagine-image-2.0/text-to-image via the hiapi API: curl, Python, and a Working Request

How to Use grok-imagine-image-2.0/text-to-image via the hiapi API: curl, Python, and a Working Request

How to Use the qwen-image-3.0 API: curl, Python, and a Working Request

How to Use the qwen-image-3.0 API: curl, Python, and a Working Request

How to Use qwen-image-3.0-pro via the hiapi API: curl, Python, and a Working Request

How to Use qwen-image-3.0-pro via the hiapi API: curl, Python, and a Working Request

Start generating