The Qwen Image text-to-image API on Novita AI generates images from text prompts using the 20B Qwen Image model — the same foundation that powers the Qwen Image Edit API for precise editing tasks. This quick start covers the full async workflow: submit a generation request, get a task ID, poll for completion, and retrieve your image URL. The endpoint is POST https://api.novita.ai/v3/async/qwen-image-txt2img.
When to Use This Quick Start
Use this guide when you need to:
- Generate images from text prompts with high-quality text rendering in English or Chinese via
POST /v3/async/qwen-image-txt2img. - Build pipelines that create posters, graphic assets, or illustrated content where text legibility inside the image matters.
- Prototype quickly against a hosted API rather than running the 20B model on local GPU infrastructure.
The Qwen Image model is especially strong at generating images with readable, styled text embedded in the output — think posters, signs, product mockups, and cover graphics. If your use case involves editing an existing image rather than generating from scratch, see the Qwen Image Edit API instead. If you want a full overview of the Qwen Image model capabilities and benchmarks, Novita AI’s Qwen Image launch post covers the architecture and benchmark results in detail.
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:
export NOVITA_API_KEY="your_api_key_here"
Keep the key out of client-side code, frontend bundles, and version control.
Step 2: Confirm the Endpoint and Model
| Item | Value |
|---|---|
| Generation endpoint | POST https://api.novita.ai/v3/async/qwen-image-txt2img |
| Result polling endpoint | GET https://api.novita.ai/v3/async/task-result?task_id=<id> |
| Model | Qwen Image (20B MMDiT) |
| API docs | Novita AI Qwen Image txt2img reference |
The API follows a two-step async pattern common to all Novita AI image generation endpoints. The generation call returns only a task_id; you poll the result endpoint separately until the task completes.
Pricing is $0.02 per image, consistent with the Qwen Image Edit endpoint. Verify the current rate on the Novita AI pricing page before building a cost estimate.
Step 3: Send Your First Request
POST to the generation endpoint with a prompt and an optional size:
curl -s -X POST https://api.novita.ai/v3/async/qwen-image-txt2img \
-H "Authorization: Bearer $NOVITA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A cinematic mountain landscape at sunrise, warm golden light, ultra-detailed, 8K",
"size": "1024*1024"
}'
A successful 200 response returns:
{
"task_id": "abc123..."
}
Save the task_id. You will use it in the next step.
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"
The response includes a status field. Keep polling until status is TASK_STATUS_SUCCEED:
{
"task": {
"task_id": "abc123...",
"status": "TASK_STATUS_SUCCEED"
},
"images": [
{
"image_url": "https://...",
"image_url_ttl": "3600",
"image_type": "png"
}
]
}
The image_url is a time-limited URL — the image_url_ttl value (in seconds) tells you how long it stays valid. Download the image promptly or proxy it through your own storage if you need long-term access.
Status values to handle:
| Status | Meaning |
|---|---|
TASK_STATUS_QUEUED | Request is queued, not yet started |
TASK_STATUS_PROCESSING | Generation in progress |
TASK_STATUS_SUCCEED | Image is ready; read images[0].image_url |
TASK_STATUS_FAILED | Generation failed; check task.reason |
Python Example: End-to-End
This script submits a generation request, polls until complete, and prints the image URL.
import os
import time
import requests
API_KEY = os.environ["NOVITA_API_KEY"]
BASE_URL = "https://api.novita.ai"
def generate_image(prompt: str, size: str = "1024*1024") -> str:
response = requests.post(
f"{BASE_URL}/v3/async/qwen-image-txt2img",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
json={"prompt": prompt, "size": size},
)
response.raise_for_status()
return response.json()["task_id"]
def poll_result(task_id: str, interval: float = 2.0, max_attempts: int = 60) -> str:
for _ in range(max_attempts):
response = requests.get(
f"{BASE_URL}/v3/async/task-result",
headers={"Authorization": f"Bearer {API_KEY}"},
params={"task_id": task_id},
)
response.raise_for_status()
data = response.json()
status = data["task"]["status"]
if status == "TASK_STATUS_SUCCEED":
return data["images"][0]["image_url"]
elif status == "TASK_STATUS_FAILED":
reason = data["task"].get("reason", "unknown")
raise RuntimeError(f"Generation failed: {reason}")
time.sleep(interval)
raise TimeoutError(f"Task {task_id} did not complete after {max_attempts} polls")
if __name__ == "__main__":
prompt = (
"A poster reading 'Welcome to Novita AI' in bold neon letters "
"against a dark city skyline at night, cinematic lighting"
)
task_id = generate_image(prompt, size="1024*1024")
print(f"Task ID: {task_id}")
image_url = poll_result(task_id)
print(f"Image URL: {image_url}")
cURL Example
Two-command pattern for the full workflow:
# Step 1: Submit generation request
TASK_ID=$(curl -s -X POST https://api.novita.ai/v3/async/qwen-image-txt2img \
-H "Authorization: Bearer $NOVITA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A serene Japanese garden with cherry blossoms, koi pond, morning mist, watercolor style",
"size": "1024*1536"
}' | python3 -c "import sys,json; print(json.load(sys.stdin)['task_id'])")
echo "Task ID: $TASK_ID"
# Step 2: Poll until complete
while true; do
STATUS=$(curl -s "https://api.novita.ai/v3/async/task-result?task_id=$TASK_ID" \
-H "Authorization: Bearer $NOVITA_API_KEY")
STATE=$(echo $STATUS | python3 -c "import sys,json; print(json.load(sys.stdin)['task']['status'])")
echo "Status: $STATE"
if [ "$STATE" = "TASK_STATUS_SUCCEED" ]; then
echo $STATUS | python3 -c "import sys,json; print(json.load(sys.stdin)['images'][0]['image_url'])"
break
elif [ "$STATE" = "TASK_STATUS_FAILED" ]; then
echo "Generation failed"
break
fi
sleep 2
done
Key Parameters
| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
prompt | string | Yes | — | Text description of the image to generate. Supports English and Chinese. |
size | string | No | 1024*1024 | Width × height in pixels, formatted as W*H. Each dimension: 256–1536. |
Size options to consider:
| Use case | Recommended size |
|---|---|
| Square (social, profile) | 1024*1024 |
| Portrait (mobile, poster) | 1024*1536 |
| Landscape (banner, thumbnail) | 1536*1024 |
There is no separate negative_prompt, steps, or cfg_scale parameter on this endpoint — the model handles those decisions internally. Focus your prompt on what the image should contain and its visual style.
What Qwen Image Generates Well
The 20B MMDiT architecture gives Qwen Image a genuine advantage in a few specific areas:
Text in images. Most image generation models struggle with readable text — words blur, letters swap, and multi-line layouts collapse. Qwen Image handles English and Chinese text with noticeably better accuracy. Posters, signs, labels, and captioned graphics are viable use cases rather than a coin-flip.
Semantic consistency. When a prompt describes a scene with multiple elements and specific spatial relationships, Qwen Image tends to honour the layout intent more reliably than smaller or older architectures.
Prompt-following at scale. Long, detailed prompts that describe multiple attributes — scene, lighting, style, color palette, specific objects — produce outputs that reflect the full prompt rather than latching onto one keyword.
Where it is less suited: real-time or interactive generation workflows. The async pattern means there is inherent latency between request and result. If your use case requires sub-second feedback, this endpoint is not the right fit.
Common Errors and Fixes
401 Unauthorized: Check that the Authorization header is formatted as Bearer <key> with a space after Bearer. Verify the key is active in the Novita AI console.
400 Bad Request on size: The size parameter must use * as the separator (e.g., 1024*1024), not x, ×, or a JSON array. Each dimension must be between 256 and 1536.
TASK_STATUS_FAILED with no reason: Usually caused by a prompt that triggers content filtering. Simplify the prompt and retry. Avoid prompts with explicit violence, sexual content, or content that may match safety filters.
Image URL expired (403 or 404 on the URL): The image_url_ttl field tells you how long the URL is valid. Download the image immediately after polling succeeds, or store it in your own object storage.
Slow polling: Generation time varies with server load. Starting poll at 2-second intervals is reasonable. If the task is still TASK_STATUS_QUEUED after 10 seconds, continue polling — queue depth can spike during peak usage.
FAQ
Is there an OpenAI-compatible endpoint for Qwen Image txt2img?
No. The /v3/async/qwen-image-txt2img endpoint uses Novita AI’s native async image API, not the OpenAI image generation format. If you need OpenAI-compatible image generation, Novita AI offers FLUX and SDXL models through compatible endpoints — see the Novita AI docs.
What is the difference between this endpoint and the Qwen Image Edit endpoint?
This endpoint generates images from a text prompt only — no input image is needed. The Qwen Image Edit endpoint takes an existing image plus a text instruction and modifies the image accordingly. Use txt2img when you are creating from scratch; use edit when you need to change something in an existing image.
Does the model support aspect ratios other than square?
Yes. Use the size parameter to set width and height independently anywhere from 256 to 1536 pixels per dimension. Tall ratios (e.g., 1024*1536) work well for portrait content; wide ratios (e.g., 1536*1024) suit banners and thumbnails.
How do I get consistent results across multiple generations?
There is no seed parameter on the txt2img endpoint. Each request produces a different result. If you need reproducible output, save the image URL immediately and store the image in your own storage rather than re-generating.
Can I use this API in a batch job?
Yes. Submit multiple generation requests and collect the task IDs, then poll them in parallel. Each request returns its own task_id, so batch workflows are straightforward — you do not need to wait for one to finish before submitting the next.
