alibaba/qwen-image-2.1/editÀ partir de 6 crédits par image· Modifier une image

L’édition d’image Qwen Image 2.1 retouche une à dix images de référence selon une instruction écrite et renvoie une image en 1k, 1.5k ou 2k. Elle gère aussi les retouches locales avec un masque noir et blanc, où le blanc est repeint.

Appelez-le avec le nom de modèle alibaba/qwen-image-2.1/edit sur POST /jobs/createTask, à partir de 6 crédits par image (0,06 $US). Les nouveaux comptes reçoivent 30 crédits gratuits pour l’essayer d’abord dans le Playground.

  • Créer une image
  • Modifier une image
  • Jusqu’à 2K
  • Jusqu’à 10 images de référence
  • 15 formats d’image
Nom du modèlealibaba/qwen-image-2.1/edit
EndpointPOST https://api.popnow.ai/api/v1/jobs/createTask
# 1. Create the task. Keep the Idempotency-Key if you retry after a network error.
export IDEMPOTENCY_KEY="$(uuidgen)"
curl -X POST https://api.popnow.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $POPNOW_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d '{
  "model": "alibaba/qwen-image-2.1/edit",
  "input": {
    "prompt": "A ceramic teapot on a linen cloth, soft window light, muted palette",
    "image_urls": [
      "https://media.popnow.ai/influencer/examples/marco.webp"
    ],
    "aspect_ratio": "1:1",
    "resolution": "1k",
    "background": "opaque",
    "output_format": "jpeg"
  }
}'

# 2. Copy data.taskId from the response, then poll until state is succeeded, failed, canceled or expired.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $POPNOW_API_KEY"

L’input est construit à partir du schéma ci-dessous : il passe la validation tel quel. Remplacez le prompt et les liens par les vôtres.

Prix

OptionCrédits par image≈ USD
resolution 1K5,40,054 $US
resolution 2K7,20,072 $US
resolution 1.5K10,80,11 $US

1 crédit = 0,01 $ · Toutes les options et leur prix : GET /models/alibaba/qwen-image-2.1/edit

Chaque tâche est arrondie au crédit entier supérieur : une exécution au palier le plus bas coûte donc 6 crédits par image (0,06 $US).

Limites

Résolutions
1K · 1.5K · 2K
Formats d’image
1:1 · 16:9 · 9:16 · 4:3 · 3:4 · 3:2 +9
Images de référence
10
Longueur du prompt (caractères)
5,000
Taille maximale d’envoi
10 MB

Paramètres

Ces champs viennent du schéma avec lequel nous vérifions chaque requête. Les champs qui n’y figurent pas sont refusés.

  • promptstringObligatoire

    Describe the subject, composition, lighting, and any wording to render.

    Plage
    1 – 5000 chars
  • image_urlsarray<string>ObligatoireModifie le prix

    Les photos à retoucher ou combiner. Dites dans le prompt ce que chacune apporte.

    Plage
    1 – 10 items · image/jpeg, image/png, image/webp, image/gif · ≤ 10 MB
  • mask_urlstringFacultatif

    Peignez la zone qui doit changer.

    Plage
    image/jpeg, image/png, image/webp, image/gif · ≤ 10 MB
  • aspect_ratiostringFacultatif

    La forme du cadre : large, carrée ou verticale.

    Par défaut
    "1:1"
    Valeurs acceptées
    "1:1""16:9""9:16""4:3""3:4""3:2""2:3""21:9""9:21""2:1""1:2""3:1""1:3""5:4""4:5"
  • resolutionstringFacultatifModifie le prix

    Taille de sortie. Plus c’est grand, plus c’est net et plus c’est cher.

    Par défaut
    "1k"
    Valeurs acceptées
    "1k""1.5k""2k"
  • enable_prompt_expansionbooleanFacultatif

    Laisse le modèle enrichir un prompt court.

    Par défaut
    true
  • backgroundstringFacultatif

    Garder, supprimer ou remplacer l’arrière-plan.

    Par défaut
    "opaque"
    Valeurs acceptées
    "opaque""transparent"
  • output_formatstringFacultatif

    Le type de fichier du résultat.

    Par défaut
    "jpeg"
    Valeurs acceptées
    "jpeg""png""webp"
  • seedintegerFacultatif

    Le même nombre donne un résultat reproductible.

    Plage
    0 – 2147483647
Schéma JSON brut
{
  "additionalProperties": false,
  "properties": {
    "aspect_ratio": {
      "default": "1:1",
      "description": "Output aspect ratio.",
      "enum": [
        "1:1",
        "16:9",
        "9:16",
        "4:3",
        "3:4",
        "3:2",
        "2:3",
        "21:9",
        "9:21",
        "2:1",
        "1:2",
        "3:1",
        "1:3",
        "5:4",
        "4:5"
      ],
      "type": "string"
    },
    "background": {
      "default": "opaque",
      "description": "opaque keeps a normal background; transparent returns the subject alone on a real alpha channel (needs output_format png or webp).",
      "enum": [
        "opaque",
        "transparent"
      ],
      "type": "string"
    },
    "enable_prompt_expansion": {
      "default": true,
      "description": "Rewrite the prompt into a fuller scene description before generating. On by default; turn it off to have the prompt followed word for word.",
      "type": "boolean"
    },
    "image_urls": {
      "description": "One to ten reference images. Each one you add raises the quote.",
      "items": {
        "contentMediaType": [
          "image/jpeg",
          "image/png",
          "image/webp",
          "image/gif"
        ],
        "format": "uri",
        "minLength": 1,
        "type": "string"
      },
      "maxItems": 10,
      "minItems": 1,
      "type": "array"
    },
    "mask_url": {
      "contentMediaType": [
        "image/jpeg",
        "image/png",
        "image/webp",
        "image/gif"
      ],
      "description": "Optional black-and-white mask for local editing: white is the area to repaint, black is kept. Use it with exactly one reference image.",
      "format": "uri",
      "type": "string"
    },
    "output_format": {
      "default": "jpeg",
      "description": "Container of the returned image.",
      "enum": [
        "jpeg",
        "png",
        "webp"
      ],
      "type": "string"
    },
    "prompt": {
      "description": "Describe the subject, composition, lighting, and any wording to render.",
      "maxLength": 5000,
      "minLength": 1,
      "type": "string"
    },
    "resolution": {
      "default": "1k",
      "description": "Output resolution tier.",
      "enum": [
        "1k",
        "1.5k",
        "2k"
      ],
      "type": "string"
    },
    "seed": {
      "description": "Random seed for controlled comparisons.",
      "maximum": 2147483647,
      "minimum": 0,
      "type": "integer"
    }
  },
  "required": [
    "prompt",
    "image_urls"
  ],
  "type": "object"
}

Un vrai résultat de Qwen Image 2.1

Gold gown rooftop
PromptDress the woman from Image 1 in the molten-gold satin gown from Image 2 - the same deep cowl back, the same thin gold chain straps, the same floor-length bias-cut drape. Keep her face, her black bob and her calm expression. Put her on a rooftop terrace at night, glancing back over her shoulder so the open cowl back faces the camera, city lights blurred behind her, a single warm lamp raking across the satin. Fashion editorial, 35mm film grain.
La même requête via l’API
{
  "model": "alibaba/qwen-image-2.1/edit",
  "input": {
    "prompt": "Dress the woman from Image 1 in the molten-gold satin gown from Image 2 - the same deep cowl back, the same thin gold chain straps, the same floor-length bias-cut drape. Keep her face, her black bob and her calm expression. Put her on a rooftop terrace at night, glancing back over her shoulder so the open cowl back faces the camera, city lights blurred behind her, a single warm lamp raking across the satin. Fashion editorial, 35mm film grain.",
    "image_urls": [
      "https://media.popnow.ai/influencer/examples/marco.webp"
    ],
    "aspect_ratio": "3:4",
    "resolution": "1k",
    "background": "opaque",
    "output_format": "jpeg"
  }
}

Ce résultat part d’un fichier envoyé : mettez votre propre lien à la place du lien d’exemple.

Réponses, interrogation et callbacks

Tous les modèles fonctionnent de la même façon : créez une tâche, puis interrogez-la ou attendez le callback.

Connaître le prix d’abord

cURL
curl -X POST https://api.popnow.ai/api/v1/jobs/quote \
  -H "Authorization: Bearer $POPNOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "model": "alibaba/qwen-image-2.1/edit",
  "input": {
    "prompt": "A ceramic teapot on a linen cloth, soft window light, muted palette",
    "image_urls": [
      "https://media.popnow.ai/influencer/examples/marco.webp"
    ],
    "aspect_ratio": "1:1",
    "resolution": "1k",
    "background": "opaque",
    "output_format": "jpeg"
  }
}'

Même corps que createTask. Renvoie le débit attendu et le débit maximal possible, sans rien lancer.

Acceptée

HTTP
HTTP/1.1 202 Accepted

{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued"
  },
  "request_id": "req_example_create"
}

HTTP 202 signifie que la tâche est acceptée et que les crédits sont réservés, pas encore débités. Le débit final ne dépasse jamais la réservation.

Vérifier l’état

cURL
curl "https://api.popnow.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $POPNOW_API_KEY"

Interrogez toutes les quelques secondes en espaçant progressivement, et arrêtez dès que state vaut succeeded, failed, canceled ou expired.

Tâche terminée

JSON
{
  "code": 200,
  "msg": "success",
  "data": {
    "taskId": "task_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "model": "alibaba/qwen-image-2.1/edit",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "url": "https://cdn.popnow.ai/tasks/task_01k3m8x9q2z4v7n5p6r8s0t1w3/output.png?signature=FROM_RESPONSE",
          "expiresAt": "2026-10-17T12:20:00Z",
          "mime": "image/png",
          "width": 1024,
          "height": 1024
        }
      ]
    },
    "settled": true
  },
  "request_id": "req_example_record"
}

Téléchargez depuis l’url avant expiresAt. Besoin d’un nouveau lien plus tard ? Demandez-le à POST /common/download-url.

Vérifier un callback

Node.js
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const app = express();
// express.raw keeps the exact bytes that were signed; express.json would not match.
app.post("/hooks/popnow", express.raw({ type: "application/json" }), (req, res) => {
  const timestamp = req.header("X-Webhook-Timestamp");
  const signature = req.header("X-Webhook-Signature") ?? "";
  const body = JSON.parse(req.body.toString("utf8"));
  const taskId = body.data?.taskId ?? body.task_id;
  const digest = createHash("sha256").update(req.body).digest("hex");
  const expected = createHmac("sha256", process.env.POPNOW_WEBHOOK_SECRET)
    .update(`${taskId}.${timestamp}.${digest}`)
    .digest("base64");
  const ok = expected.length === signature.length && timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
  // Check the signature first, then reject anything older than five minutes.
  if (!ok || Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return res.status(401).end();
  res.status(200).end(); // answer fast, then fetch the task and store its files
});

Avec une callBackUrl, nous vous envoyons la tâche terminée. Vérifiez la signature sur le corps brut avant de lui faire confiance.

Envoyer un fichier local

cURL
curl -X POST https://api.popnow.ai/api/v1/common/upload-url \
  -H "Authorization: Bearer $POPNOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"contentType": "image/png", "bytes": 482113}'

# PUT the file bytes to data.uploadUrl with every header in data.headers, then commit it:
curl -X POST https://api.popnow.ai/api/v1/files/$FILE_ID/commit \
  -H "Authorization: Bearer $POPNOW_API_KEY"
# The commit returns a popnow://f/... reference. Put it in any image, video or
# audio field of the task input instead of a public https URL.

Les liens https publics fonctionnent tels quels. Les fichiers locaux passent d’abord par upload-url et commit.