Qwen Try-On API

Image generation and editing with Qwen-Image-2.1. JSON in, JSON out. No API key required.

Base URL http://ownv2.neuraa.in

Endpoints

MethodPathPurpose
POST/tryonGenerate / edit an image
GET/tryon/{jobId}Status or result of an async job
GET/jobs/{jobId}Saved job: prompt, params, input and output images
GET/healthService and model readiness
GET/openapi.jsonOpenAPI 3 spec
GET/swaggerInteractive Swagger UI (needs internet for its assets)
POST/tryon

Send a prompt, optional negative prompt, optional images and parameters. Waits for the result and returns the image as base64 PNG.

Request body (JSON)

FieldTypeRequiredDescription
promptstringyesWhat to generate or change (max 8000 chars). Refer to inputs as image 1, image 2 ...
negative_promptstringnoWhat to avoid. Needs true_cfg_scale above 1.
imagesarray of stringno0-10 images: https URL, data URL or raw base64 (max 25 MB each).
paramsobjectnoSettings below. May also be sent at the top level.
asyncbooleannotrue = return a jobId at once (202), then poll GET /tryon/{jobId}.

params

ParamRangeDefaultDescription
seedintegerrandomSame seed + inputs = same image.
steps1 - 10030More steps = slower, finer.
true_cfg_scale1 - 201Guidance (alias guidance_scale). Use 3-5 so the negative prompt works.
width / height256 - 2752autoSend both together. Rounded down to a multiple of 16.
output_resolution512 - 20481024Used when width/height are not set.
num_images1 - 41Number of variations returned.
rgbatrue/falsefalseTransparent background.

Example request

curl -X POST http://ownv2.neuraa.in/tryon \
  -H "Content-Type: application/json" \
  -d '{"prompt": "Change the background to a sunset beach", "negative_prompt": "blurry, low quality", "images": ["https://example.com/photo.jpg", "data:image/png;base64,iVBORw0KGgo..."], "params": {"seed": 42, "steps": 30, "true_cfg_scale": 4.0, "width": 1024, "height": 1024, "num_images": 1}}'
{
  "prompt": "Change the background to a sunset beach",
  "negative_prompt": "blurry, low quality",
  "images": [
    "https://example.com/photo.jpg",
    "data:image/png;base64,iVBORw0KGgo..."
  ],
  "params": {
    "seed": 42,
    "steps": 30,
    "true_cfg_scale": 4.0,
    "width": 1024,
    "height": 1024,
    "num_images": 1
  }
}

Responses

200 Success - images are base64 PNGs
{
  "code": 200,
  "message": "ok",
  "data": {
    "jobId": "c463b6c90eac",
    "mimeType": "image/png",
    "seed": 42,
    "genSeconds": 8.2,
    "images": [
      "<base64 PNG>"
    ]
  }
}
202 Queued (only when async is true)
{
  "code": 202,
  "message": "queued",
  "data": {
    "jobId": "864da964a5c4",
    "state": "queued"
  }
}
400 Invalid input
{
  "code": 400,
  "message": "prompt required"
}
503 Model busy or loading
{
  "code": 503,
  "message": "model busy",
  "retryable": true
}
504 Timed out
{
  "code": 504,
  "message": "generation timed out",
  "jobId": "864da964a5c4",
  "retryable": true
}
Decode data.images[0] from base64 and save it as .png to get the picture.
GET/tryon/{jobId}

Poll every 1-3 s after sending "async": true. data.state is queued, running or done.

200 Running
{
  "code": 200,
  "message": "running",
  "data": {
    "jobId": "864da964a5c4",
    "state": "running",
    "step": 12,
    "steps": 30,
    "position": 0,
    "etaSeconds": 6.1
  }
}
200 Done
{
  "code": 200,
  "message": "ok",
  "data": {
    "jobId": "864da964a5c4",
    "state": "done",
    "mimeType": "image/png",
    "seed": 1,
    "genSeconds": 4.4,
    "images": [
      "<base64 PNG>"
    ]
  }
}
404 Unknown job
{
  "code": 404,
  "message": "job not found"
}
502 Generation failed
{
  "code": 502,
  "message": "generation error",
  "data": {
    "jobId": "864da964a5c4",
    "state": "error",
    "detail": "..."
  }
}
GET/health
200 Ready
{
  "status": "ok",
  "model": "ready"
}
503 Model loading or unreachable
{
  "status": "degraded",
  "model": "loading model..."
}

Saved jobs

Every job is saved with its job ID, prompt, negative prompt, parameters, input images and output images. The job ID is returned by POST /tryon (data.jobId, plus data.jobUrl).

MethodPathPurpose
GET/jobs/{jobId}Full record of one job (open, by ID)
GET/jobs/{jobId}/input/{n}Input image n (PNG), n starts at 0
GET/jobs/{jobId}/output/{n}Output image n (PNG), n starts at 0
GET/jobs?limit=50&offset=0&status=done&q=textList all jobs, newest first. Needs the history key: Authorization: Bearer <key>

GET /jobs/{jobId}

200 Job record
{
  "code": 200,
  "message": "ok",
  "data": {
    "jobId": "303b04234bef",
    "status": "done",
    "prompt": "In image 1, change the top to a red t-shirt",
    "negativePrompt": "blurry",
    "createdAt": "2026-10-20T15:41:39+00:00",
    "genSeconds": 16.2,
    "totalSeconds": 16.6,
    "seed": 2126666741,
    "width": 1024,
    "height": 1024,
    "error": null,
    "params": {
      "steps": 20,
      "true_cfg_scale": 1.0,
      "num_images": 1
    },
    "inputImages": [
      {
        "index": 0,
        "url": "http://ownv2.neuraa.in/jobs/303b04234bef/input/0"
      }
    ],
    "outputImages": [
      {
        "index": 0,
        "url": "http://ownv2.neuraa.in/jobs/303b04234bef/output/0"
      }
    ]
  }
}
404 Unknown job
{
  "code": 404,
  "message": "job not found"
}
401 Listing without the key
{
  "code": 401,
  "message": "listing jobs needs the history key"
}

Errors

Every error is JSON: {"code": <http status>, "message": "..."}

HTTPMeaning
400Bad input (message names the problem: prompt required, parameter out of range, bad image/URL ...)
404Unknown path or jobId
405Wrong HTTP method
409Job was cancelled
413Request body too large (max 256 MB)
502Generation / model server error
503Model busy or still loading (retryable)
504Timed out after 600 s (use async)

Image input

Each item in images is an https URL, a data URL (data:image/png;base64,...) or raw base64. Max 10 images, 25 MB each. URLs must be https and public (private/localhost addresses are rejected). If a site blocks downloads, send the image as base64.