The Qwen Image Edit API on Novita AI modifies an existing image using a natural language instruction, powered by the 20B Qwen-Image model. This quick start covers the complete async workflow: submit an edit request with your source image and prompt, receive a task ID, poll until the edit completes, and retrieve the edited image URL. The endpoint is POST https://api.novita.ai/v3/async/qwen-image-edit.
Table of Contents
When to Use This Quick Start
Use this guide when you need to:
- Modify an existing image through a text instruction — changing backgrounds, swapping styles, removing elements, rotating objects, or adjusting clothing without rebuilding the image from scratch.
- Keep untouched regions intact while applying targeted edits. The model’s dual-path architecture (Qwen2.5-VL for semantic understanding + VAE encoder for appearance preservation) is specifically designed to prevent edits from bleeding into areas you didn’t describe.
- Edit text in images precisely. Qwen Image Edit handles bilingual English and Chinese text replacements in signs, posters, and branded assets — preserving font, size, and surrounding visual style in a way most image generators fail at.
If you are generating a new image from a prompt only (no input image required), use the Qwen Image txt2img quick start instead. For a full overview of the model’s capabilities, benchmarks, and architecture, see the Qwen-Image on Novita AI launch post.
Step 1: Get Your Novita API Key
Create a Novita AI account and navigate to API key management. Generate a key and store it as an environment variable before running any of the code examples below:
export NOVITA_API_KEY="your_api_key_here"
Keep the key out of client-side code, frontend bundles, and version control. If the key is compromised, rotate it from the same settings page.
Step 2: Confirm the Endpoint and Model
| Item | Value |
|---|---|
| Edit endpoint | POST https://api.novita.ai/v3/async/qwen-image-edit |
| Result polling endpoint | GET https://api.novita.ai/v3/async/task-result?task_id=<id> |
| Model | Qwen Image Edit (20B MMDiT, dual-path architecture) |
| API docs | Novita AI Qwen Image Edit reference |
The API is async. The edit call returns a task_id immediately; you poll the result endpoint until the status is TASK_STATUS_SUCCEED. This is the same two-step pattern used by all Novita AI image generation endpoints, including the txt2img endpoint.
Pricing is $0.02 per image. Verify the current rate on the Novita AI pricing page before building a cost model.
Step 3: Send Your First Edit Request
POST to the edit endpoint with your source image and the edit instruction:
curl -s -X POST https://api.novita.ai/v3/async/qwen-image-edit \
-H "Authorization: Bearer $NOVITA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Change the background to a snowy mountain landscape",
"image": "https://example.com/my-portrait.jpg"
}'
A successful 200 response returns:
{
"task_id": "abc123..."
}
Save the task_id — you need it to retrieve the edited image.
Step 4: Poll for Your Result
GET the task result endpoint with the task_id as a query parameter:
curl -s "https://api.novita.ai/v3/async/task-result?task_id=abc123..." \
-H "Authorization: Bearer $NOVITA_API_KEY"
Keep polling until the task_status field is TASK_STATUS_SUCCEED:
{
"task_status": "TASK_STATUS_SUCCEED",
"images": [
{
"image_url": "https://...",
"image_url_ttl": "86400",
"image_type": "JPEG"
}
]
}
The image_url expires after the TTL window (typically 24 hours). Download and store the result in your own object storage if you need long-term access.
Status values to handle:
| Status | Meaning |
|---|---|
TASK_STATUS_QUEUED | Request is waiting in the queue; keep polling |
TASK_STATUS_PROCESSING | Edit is in progress; keep polling |
TASK_STATUS_SUCCEED | Complete; read the edited image from images[0].image_url |
TASK_STATUS_FAILED | Generation failed; check the error field for the reason |
Step 5: Check Pricing, Limits, and Common Errors
Pricing: $0.02 per image (verify on the pricing page).
Rate limits: Check the API reference for current rate limits. If you hit a 429, reduce your request rate and implement exponential backoff on retries.
Common HTTP errors:
| Status code | Likely cause |
|---|---|
| 400 | Malformed request body — missing prompt or image, invalid image format, or unsupported input size |
| 401 | Missing or invalid API key — confirm the Authorization: Bearer <key> format |
| 429 | Rate limit exceeded — add backoff and retry logic |
| 500 | Server-side error — retry after a short delay |
If the task status is TASK_STATUS_FAILED, the response typically includes an error message. Common reasons include unsupported image formats, images that exceed size limits, or prompts that trigger content safety filters.
Python Example
This script submits an edit request, polls until complete, and prints the output image URL:
import os
import time
import requests
API_KEY = os.environ["NOVITA_API_KEY"]
BASE_URL = "https://api.novita.ai/v3/async"
def submit_edit(image: str, prompt: str, seed: int | None = None) -> str:
payload: dict = {"prompt": prompt, "image": image}
if seed is not None:
payload["seed"] = seed
response = requests.post(
f"{BASE_URL}/qwen-image-edit",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json=payload,
)
response.raise_for_status()
return response.json()["task_id"]
def poll_result(task_id: str, interval: float = 2.0, timeout: float = 120.0) -> dict:
deadline = time.time() + timeout
while time.time() < deadline:
response = requests.get(
f"{BASE_URL}/task-result",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"task_id": task_id},
)
response.raise_for_status()
data = response.json()
status = data.get("task_status", "")
if status == "TASK_STATUS_SUCCEED":
return data
if status == "TASK_STATUS_FAILED":
raise RuntimeError(f"Edit task failed: {data}")
time.sleep(interval)
raise TimeoutError(f"Task {task_id} did not complete within {timeout}s")
if __name__ == "__main__":
task_id = submit_edit(
image="https://example.com/product-photo.jpg",
prompt="Change the jacket to a red leather jacket, preserve the background",
)
print(f"Task ID: {task_id}")
result = poll_result(task_id)
for img in result["images"]:
print(img["image_url"])
cURL Example
Two-command workflow using jq for JSON parsing:
#!/bin/bash
# Step 1: submit the edit request
TASK_ID=$(curl -s -X POST https://api.novita.ai/v3/async/qwen-image-edit \
-H "Authorization: Bearer $NOVITA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Convert to watercolor painting style, preserve the subject and composition",
"image": "https://example.com/landscape.jpg"
}' | jq -r '.task_id')
echo "Task ID: $TASK_ID"
# Step 2: poll until complete
while true; do
RESULT=$(curl -s "https://api.novita.ai/v3/async/task-result?task_id=$TASK_ID" \
-H "Authorization: Bearer $NOVITA_API_KEY")
STATUS=$(echo "$RESULT" | jq -r '.task_status')
echo "Status: $STATUS"
if [ "$STATUS" = "TASK_STATUS_SUCCEED" ]; then
echo "$RESULT" | jq -r '.images[].image_url'
break
elif [ "$STATUS" = "TASK_STATUS_FAILED" ]; then
echo "Task failed:"
echo "$RESULT" | jq .
exit 1
fi
sleep 2
done
Install jq with apt install jq (Debian/Ubuntu) or brew install jq (macOS) if it is not already present.
Key Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
prompt | string | Yes | — | Natural language instruction describing the desired edit |
image | string | Yes | — | Source image as a URL or base64-encoded string |
seed | integer | No | random | Fixed seed for reproducible outputs across multiple runs |
output_format | string | No | jpeg | Output format — refer to API docs for accepted values |
Writing effective prompts: Specificity matters. “Change the text on the billboard to ‘Summer Sale’” gives the model a clear, bounded task. “Improve the image” does not. When you want to change one element and leave everything else intact, name what you want to preserve: “change the jacket color to red, keep the background and face unchanged.” This helps the VAE encoder path do its job of locking untouched regions.
Using seed for iteration: When tuning a prompt, fixing the seed lets you compare edits directly — output variation comes from your prompt change, not from random sampling. Once you find a prompt that works, remove the seed constraint if you want output diversity across multiple edits.
Typical Use Cases
Background replacement: “Replace the background with a minimalist white studio” — Qwen Image Edit preserves the subject’s edges and lighting while swapping the environment. Works reliably when the subject has a clear boundary against the original background.
Text in images: Replacing store signs, poster headlines, or product labels with new text — including Chinese and English. The model preserves font style and surrounding visual context better than generative inpainting approaches that tend to regenerate the entire region.
Style conversion: “Convert to oil painting style” or “make this look like a pencil sketch” applied to a source image rather than described from scratch. The VAE encoder path preserves the original composition and object placement while the prompt drives the style transformation.
Object-level changes: Swapping clothing, changing colors of specific items, adding or removing accessories. The instruction should name the specific element being changed to prevent the edit from affecting adjacent regions.
IP conversion and object rotation: The model supports view synthesis changes (e.g., rotating an object to show a different angle) and converting between visual styles for character or product imagery — use cases documented in the Qwen-Image-Edit on Novita AI overview.
Troubleshooting
Output looks unchanged: The instruction is likely underspecified. Make it more explicit about what element to target: “Change the color of the car from blue to red” rather than “make it red.”
Unwanted edits spread into unintended areas: For highly specific local edits, include explicit preservation language in your prompt: “only change X, leave Y intact.” Overly open-ended prompts give the model latitude to reinterpret the whole composition.
Task completes but image URL returns 403 or 404: The image_url_ttl field (in seconds) tells you how long the URL is valid. If you poll for the URL later than the TTL, the URL has expired. Download the image immediately after a successful poll.
401 Unauthorized: Verify the Authorization header format is exactly Bearer <key> with a space after Bearer. Confirm the key is active and not revoked in the Novita AI console.
Tasks consistently timing out: Image editing takes longer than text generation — typically 15–60 seconds under normal load. If tasks routinely exceed your timeout, increase the polling window before treating it as a failure.
FAQ
Does the source image stay on Novita’s servers?
Your image is uploaded to Novita AI’s API over HTTPS and processed on their infrastructure. Review Novita AI’s data handling policies before sending images with sensitive personal information, private health data, or confidential content.
Can I use base64-encoded images instead of a URL?
Yes. Pass the raw base64 string in the image field. Consult the API reference for any size limits on base64 payloads.
Is there a seed parameter for consistency?
Yes — the optional seed parameter pins the random state so the same prompt and image produce consistent results. Useful for iterating on prompt wording without output noise from re-sampling.
Can I use this endpoint for batch jobs?
Yes. Submit multiple edit requests in parallel and collect the task_id values, then poll them concurrently. Each request is independent.
What is the difference between this and the Qwen Image txt2img endpoint?
The edit endpoint requires a source image and produces a modified version of it. The txt2img endpoint generates an image entirely from a text prompt — no input image. Use the edit endpoint when you have existing content you want to modify; use txt2img when you are creating from scratch.
