Z Image Turbo Quick Start for Fast Text-to-Image Generation with LoRA

Z Image Turbo Quick Start for Fast Text-to-Image Generation with LoRA

Z Image Turbo is available on Novita AI through two async endpoints: POST https://api.novita.ai/v3/async/z-image-turbo for standard text-to-image generation, and POST https://api.novita.ai/v3/async/z-image-turbo-lora for generation with LoRA style models. Both follow Novita AI’s standard async pattern — submit a request, receive a task_id, then poll GET /v3/async/task-result until the image is ready. This guide covers both endpoints end-to-end: first request, polling loop, LoRA usage, and the parameter reference you need before writing production code.

When to Use This Quick Start

Use this guide when you need a verified working request for Z Image Turbo before adding error handling, batching, or production logic around it.

Z Image Turbo is designed for fast throughput. It fits workflows where:

  • Speed matters more than maximum quality — prototype pipelines, batch preview generation, or real-time applications where latency is a hard constraint.
  • You want LoRA-based style transfer without configuring the full txt2img parameter set. The dedicated LoRA endpoint accepts a loras array and handles the rest.
  • You need a simple prompt-in / image-out interface with a minimal request body.

Z Image Turbo is not the right choice when you need the full Stable Diffusion configuration surface — steps, guidance_scale, sampler_name, negative_prompt, hires_fix, refiner models, and so on. For that level of control, use the standard POST /v3/async/txt2img endpoint.

This guide covers the Novita AI-hosted API path only. It does not address self-hosting or fine-tuning.

Step 1: Get Your Novita API Key

Create a Novita AI account and navigate to API key management. Generate a key and export it:

export NOVITA_API_KEY="your_api_key_here"

Keep the key out of version control, client-side bundles, and Docker image layers.

Step 2: Confirm the Endpoints

Z Image Turbo on Novita AI uses two separate submission endpoints and one shared result endpoint:

Base T2ILoRA T2I
SubmissionPOST https://api.novita.ai/v3/async/z-image-turboPOST https://api.novita.ai/v3/async/z-image-turbo-lora
Result pollingGET https://api.novita.ai/v3/async/task-result?task_id=<id>GET https://api.novita.ai/v3/async/task-result?task_id=<id>
API referenceZ Image Turbo docsZ Image Turbo LoRA docs

Both submission endpoints return only a task_id. The result polling endpoint is identical for both — once your polling loop works for one, it works for the other.

Step 3: Send Your First Request

The base endpoint requires prompt and size. Start here before adding optional parameters:

curl -s -X POST https://api.novita.ai/v3/async/z-image-turbo \
  -H "Authorization: Bearer $NOVITA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A futuristic city skyline at dusk, neon lights, photorealistic, ultra-detailed",
    "size": "1024*1024"
  }'

A successful 200 response returns:

{
  "task_id": "abc123..."
}

Save the task_id. Nothing else is returned at submission — the generation runs asynchronously.

Two optional parameters are available on the base endpoint:

  • seed (integer): pin for reproducible outputs. The same prompt and seed combination returns consistent results.
  • enable_base64_output (boolean): when true, the result includes the image as a base64-encoded string rather than a hosted URL.

Step 4: Poll for the Result

GET the task result endpoint with 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"

A completed task returns:

{
  "task": {
    "task_id": "abc123...",
    "status": "TASK_STATUS_SUCCEED",
    "progress_percent": 100,
    "eta": 0
  },
  "images": [
    {
      "image_url": "https://...",
      "image_url_ttl": 3600,
      "image_type": "png"
    }
  ]
}

Poll every 1–2 seconds until task.status is TASK_STATUS_SUCCEED or TASK_STATUS_FAILED. The task.eta field gives an estimated remaining seconds when the task is still in queue.

image_url_ttl is the URL lifetime in seconds. Download and store the image before the TTL expires — the hosted URL is not permanent.

Step 5: Check Pricing, Limits, and Common Errors

Current pricing for Z Image Turbo is listed on the Novita AI pricing page and the Z Image Turbo model page. Verify rates before building cost estimates, as pricing can change.

Common errors:

ErrorCauseFix
401 UnauthorizedMissing or malformed API keyConfirm header is Authorization: Bearer <key>
400 Bad RequestInvalid request bodyConfirm prompt and size are strings; seed must be an integer if provided
TASK_STATUS_FAILEDGeneration rejected or erroredRead task.reason in the result response for the specific failure message
Image URL returns 403 or is expiredURL accessed after TTL elapsedDownload and store the image before image_url_ttl seconds pass

Python Example

Full workflow — submit, poll, return the image URL:

import os
import time
import requests

API_KEY = os.environ["NOVITA_API_KEY"]
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def generate_image(prompt: str, size: str = "1024*1024", seed: int = None) -> str:
    payload = {"prompt": prompt, "size": size}
    if seed is not None:
        payload["seed"] = seed

    resp = requests.post(
        "https://api.novita.ai/v3/async/z-image-turbo",
        json=payload,
        headers=HEADERS,
    )
    resp.raise_for_status()
    task_id = resp.json()["task_id"]

    while True:
        result = requests.get(
            f"https://api.novita.ai/v3/async/task-result?task_id={task_id}",
            headers=HEADERS,
        )
        result.raise_for_status()
        data = result.json()
        status = data["task"]["status"]

        if status == "TASK_STATUS_SUCCEED":
            return data["images"][0]["image_url"]
        if status == "TASK_STATUS_FAILED":
            raise RuntimeError(f"Generation failed: {data['task'].get('reason', 'unknown')}")

        time.sleep(1)

if __name__ == "__main__":
    url = generate_image(
        "A futuristic city skyline at dusk, neon lights, photorealistic",
        size="1024*1024",
        seed=42,
    )
    print(url)

LoRA Generation

The LoRA endpoint adds a loras array to the request. Each entry takes a path (the LoRA model identifier from the Novita AI model hub) and a scale (influence weight):

curl -s -X POST https://api.novita.ai/v3/async/z-image-turbo-lora \
  -H "Authorization: Bearer $NOVITA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a portrait in anime style, soft lighting, detailed face",
    "size": "768*1024",
    "loras": [
      {
        "path": "<lora-model-path>",
        "scale": 0.8
      }
    ],
    "seed": 42
  }'

Replace <lora-model-path> with a confirmed path from the Novita AI model hub. The path format and compatible LoRA models are listed in the Z Image Turbo LoRA API reference — do not guess model paths; use only verified hub entries to avoid TASK_STATUS_FAILED results from unresolvable paths.

Polling the LoRA result works identically to the base endpoint.

Python version of the same LoRA workflow:

import os
import time
import requests

API_KEY = os.environ["NOVITA_API_KEY"]
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

def generate_with_lora(
    prompt: str,
    lora_path: str,
    lora_scale: float = 0.8,
    size: str = "1024*1024",
    seed: int = None,
) -> str:
    payload = {
        "prompt": prompt,
        "size": size,
        "loras": [{"path": lora_path, "scale": lora_scale}],
    }
    if seed is not None:
        payload["seed"] = seed

    resp = requests.post(
        "https://api.novita.ai/v3/async/z-image-turbo-lora",
        json=payload,
        headers=HEADERS,
    )
    resp.raise_for_status()
    task_id = resp.json()["task_id"]

    while True:
        result = requests.get(
            f"https://api.novita.ai/v3/async/task-result?task_id={task_id}",
            headers=HEADERS,
        )
        result.raise_for_status()
        data = result.json()
        status = data["task"]["status"]

        if status == "TASK_STATUS_SUCCEED":
            return data["images"][0]["image_url"]
        if status == "TASK_STATUS_FAILED":
            raise RuntimeError(f"Generation failed: {data['task'].get('reason', 'unknown')}")

        time.sleep(1)

LoRA scale guidance

scale controls how strongly the LoRA style is applied. A value of 0.8 is a reasonable default. Go lower (0.4–0.6) if the prompt detail is getting overridden by the LoRA style; go higher (0.9–1.0) if the style is not appearing strongly enough. Stacking multiple LoRAs with high scale values can degrade coherence — test each LoRA individually first.

Some LoRA models require trigger words in the prompt to activate their style. Check the model listing on the Novita AI hub for any required keywords before testing.

Key Parameters

Base endpoint (/v3/async/z-image-turbo)

ParameterTypeRequiredDescription
promptstringYesText description of the target image
sizestringYesOutput dimensions as "width*height", e.g. "1024*1024"
seedintegerNoReproducibility pin; same seed + prompt returns consistent outputs
enable_base64_outputbooleanNoWhen true, returns image as base64 string instead of a hosted URL

LoRA endpoint (/v3/async/z-image-turbo-lora)

ParameterTypeRequiredDescription
promptstringYesText prompt; include LoRA trigger words if required
sizestringYesOutput dimensions as "width*height"
lorasarrayYesOne or more LoRA objects
loras[].pathstringYesLoRA model path from the Novita AI model hub
loras[].scalenumberYesInfluence weight; 0.8 is a common starting point
seedintegerNoReproducibility pin

enable_base64_output is not listed on the LoRA endpoint in current documentation. Use the result URL from polling for image retrieval.

Troubleshooting

Task stays in TASK_STATUS_PENDING for longer than expected. Queue depth varies with platform load. The task.eta field in the polling response returns an estimated wait in seconds. For latency-sensitive production paths, consider submitting requests and polling in parallel across multiple task IDs.

TASK_STATUS_FAILED immediately or after a short wait. Read task.reason in the result. Common causes: invalid size string format, an unresolvable LoRA path, or a prompt that triggered content filtering. Isolate with a minimal request.

Image URL returns 403. The URL lifetime is controlled by image_url_ttl (in seconds). If you request the URL after that window, access is denied. Fetch and store the image data immediately after polling succeeds.

LoRA style is not appearing in the output. Try increasing scale toward 1.0. Verify the LoRA requires no trigger words — if it does, add them to the prompt.

400 Bad Request on the LoRA endpoint. Confirm the loras field is an array (not an object), and that both path and scale are present in each entry.

FAQ

What is Z Image Turbo designed for?

Z Image Turbo is optimized for fast text-to-image generation. It suits applications that need quick throughput: preview generation, batch pipelines, and use cases where LoRA-based stylization matters more than the fine-grained diffusion control of a full SDXL workflow.

What sizes does Z Image Turbo support?

The size parameter takes a "width*height" string. Confirmed supported values are listed on the Z Image Turbo model page. Square (1024*1024) and portrait (768*1024) formats are a safe starting point, consistent with other Novita AI image endpoints.

Can I apply multiple LoRAs in one request?

The loras array accepts multiple entries. In practice, stacking LoRAs with high scale values often degrades output quality. Test each LoRA individually first, then combine with conservative scale values (0.5–0.7 per entry).

Where do I find compatible LoRA paths?

Browse the Novita AI model hub and check the Z Image Turbo LoRA API reference for the confirmed path format. Do not use paths from external sources without first verifying they resolve on the Novita platform.

Is negative_prompt supported?

Neither Z Image Turbo endpoint lists a negative_prompt parameter in current documentation. If you need to exclude subjects or styles, use positive phrasing in the prompt to steer away from unwanted content, or evaluate the standard txt2img endpoint which supports negative_prompt directly.

Can I generate multiple images in a single call?

Current documentation does not list an image_num parameter on either Z Image Turbo endpoint. For batch generation, submit multiple requests in parallel and poll their task_id values concurrently — each request is independent.

How does Z Image Turbo compare to the standard txt2img endpoint?

The standard txt2img endpoint supports a wide configuration surface: steps, guidance scale, sampler, negative prompt, Hi-Res Fix, and refiner models. Z Image Turbo trades that configurability for speed and a simpler request shape. Use txt2img when parameter control matters; use Z Image Turbo when throughput or simplicity is the priority.