HiAPI
Blog

Tutoriel

Générer des images produit aux dimensions exactes via l'API : ratios d'aspect et spécifications des plateformes e-commerce

Jul 9, 2026
Générer des images produit aux dimensions exactes via l'API : ratios d'aspect et spécifications des plateformes e-commerce

Chaque canal de vente exige des dimensions différentes pour vos images produit : Amazon veut de grandes images carrées sur fond blanc, Instagram veut un cadrage vertical 4:5, Pinterest veut des Pins 2:3, et la bannière principale de votre propre boutique a besoin d'une image ultra-large. Ce guide explique comment générer par programmation des images dans toutes ces dimensions avec l'API hiapi — en utilisant gpt-image-2 et wan2.7-image — et comment atteindre précisément la taille en pixels cible à chaque fois.

Prérequis : une clé API hiapi (à créer dans la console), ainsi que curl ou Python. Le coût total dépend du modèle et de la résolution choisis — voir la page tarifs.

Comment fonctionnent réellement les dimensions d'image sur l'API

Commençons par le point le plus déroutant : les modèles d'image sur hiapi n'acceptent pas de dimensions en pixels. Il n'y a pas de champ size, width ou height. Si vous essayez d'en passer un, l'API vous le dira clairement :

{
  "code": 400,
  "error_code": "INVALID_REQUEST",
  "message": "invalid input: <root>: additional properties 'size' not allowed"
}

Les dimensions sont plutôt contrôlées par deux champs dans input :

  • aspect_ratio — la forme du cadre, à choisir dans une liste fixe propre à chaque modèle.
  • resolution — le palier de sortie : "1K", "2K" ou "4K" (le côté long fait approximativement 1024 / 2048 / 4096 pixels ; le nombre exact de pixels varie selon le ratio, donc vérifiez toujours le fichier obtenu).

Voici les paramètres réellement acceptés par les deux modèles de ce guide (vérifiés sur l'API en production) :

gpt-image-2 wan2.7-image/text-to-image
prompt obligatoire obligatoire
aspect_ratio auto, 1:1, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 16:9, 9:16, 2:1, 1:2, 3:1, 1:3, 21:9, 9:21 — 16 valeurs au total 1:1, 16:9, 4:3, 21:9, 3:4, 9:16, 8:1, 1:8 — 8 valeurs au total
resolution 1K, 2K, 4K 1K, 2K, 4K
Capacités supplémentaires Variante image-vers-image (gpt-image-2/image-to-image) seed (entier) pour la reproductibilité
size / n en pixels non accepté non accepté

La différence pratique : gpt-image-2 couvre les ratios nécessaires aux formats des plateformes sociales et e-commerce (4:5, 2:3, 5:4 sont exclusifs à gpt-image-2), tandis que wan2.7-image ajoute des bandeaux ultra-larges 8:1/1:8, qu'aucune autre liste de ratios ne couvre — idéal pour les bannières promotionnelles étroites — et c'est un choix courant pour les images studio 4K.

Ainsi, pour contrôler précisément les dimensions, la recette se fait en deux étapes :

  1. Générez avec un ratio d'aspect correspondant, et choisissez le palier de résolution le plus petit dont le côté long atteint ou dépasse la cible (réduisez ensuite, n'agrandissez jamais).
  2. Redimensionnez localement le fichier retourné aux pixels cibles exacts — une ligne de code Pillow.

Tableau de référence des spécifications des plateformes e-commerce

Voici les exigences publiques courantes, mappées aux paramètres de l'API :

Canal Cible typique aspect_ratio resolution Remarques modèle
Image principale Amazon côté long ≥1000 pixels (le zoom s'active au-delà de 1600 pixels), carré, fond blanc pur 1:1 2K les deux conviennent
Page produit Shopify 2048×2048 recommandé 1:1 2K les deux conviennent
Fil Instagram (cadrage vertical) 1080×1350 4:5 2K gpt-image-2 uniquement
Stories / Reels / TikTok 1080×1920 9:16 2K les deux conviennent
Pin Pinterest 1000×1500 2:3 2K gpt-image-2 uniquement
Annonce Etsy 2700×2025 recommandé 4:3 4K les deux conviennent (palier 4K requis)
Bannière principale de site web par exemple 2560 pixels de large 21:9 4K les deux conviennent
Bannière promotionnelle étroite ultra-large 8:1 2K/4K wan2.7-image uniquement

(Les spécifications des plateformes évoluent ; considérez ces cibles en pixels comme des recommandations publiques courantes et vérifiez-les par rapport à la documentation actuelle de chaque plateforme.)

Exemple minimal fonctionnel (curl)

Tout passe par un point de terminaison unifié de tâches asynchrones : créez avec POST /v1/tasks, puis interrogez avec GET /v1/tasks/<id>. Créez une image carrée de style Amazon, au palier 2K :

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-image-2/text-to-image",
    "input": {
      "prompt": "Studio product photo of a stainless steel water bottle on a pure white background, centered, soft shadow, e-commerce catalog style",
      "aspect_ratio": "1:1",
      "resolution": "2K"
    }
  }'

L'id de tâche dans la réponse se trouve dans data.taskId. Interrogez-la :

curl -s https://api.hiapi.ai/v1/tasks/TASK_ID \
  -H "Authorization: Bearer sk-YOUR_KEY"

Interrogez jusqu'à ce que data.status passe à "success" (ou "fail", les détails étant sous data.error). L'URL de l'image se trouve dans data.output[0].url. Cette URL expire (l'objet de sortie contient expireAt), donc téléchargez immédiatement et réhébergez sur votre propre stockage — ne créez jamais de lien direct (hotlink) dans une fiche produit.

Script de production : un produit, tous les canaux, pixels exacts

Ce script par lots crée d'abord toutes les tâches (elles s'exécutent en parallèle sur la plateforme), interroge chacune jusqu'à achèvement, puis redimensionne aux dimensions cibles exactes avec Pillow. ImageOps.fit gère en un seul appel à la fois la réduction et tout recadrage mineur.

import os
import time
from io import BytesIO

import requests
from PIL import Image, ImageOps

API = "https://api.hiapi.ai/v1"
HDRS = {
    "Authorization": f"Bearer {os.environ['HIAPI_KEY']}",
    "Content-Type": "application/json",
}

# canal -> paramètres de génération + cible en pixels exacts
SPECS = {
    "amazon-main":    {"model": "gpt-image-2/text-to-image", "aspect_ratio": "1:1",  "resolution": "2K", "px": (1600, 1600)},
    "shopify":        {"model": "gpt-image-2/text-to-image", "aspect_ratio": "1:1",  "resolution": "2K", "px": (2048, 2048)},
    "instagram-feed": {"model": "gpt-image-2/text-to-image", "aspect_ratio": "4:5",  "resolution": "2K", "px": (1080, 1350)},
    "story-reel":     {"model": "gpt-image-2/text-to-image", "aspect_ratio": "9:16", "resolution": "2K", "px": (1080, 1920)},
    "pinterest-pin":  {"model": "gpt-image-2/text-to-image", "aspect_ratio": "2:3",  "resolution": "2K", "px": (1000, 1500)},
    "etsy-listing":   {"model": "wan2.7-image/text-to-image", "aspect_ratio": "4:3",  "resolution": "4K", "px": (2700, 2025)},
    "hero-banner":    {"model": "wan2.7-image/text-to-image", "aspect_ratio": "21:9", "resolution": "4K", "px": (2560, 1097)},
}

PROMPT = (
    "Studio product photo of a stainless steel water bottle on a pure white "
    "background, centered, soft shadow, high detail, e-commerce catalog style"
)


def create_task(model: str, prompt: str, aspect_ratio: str, resolution: str) -> str:
    body = {
        "model": model,
        "input": {"prompt": prompt, "aspect_ratio": aspect_ratio, "resolution": resolution},
    }
    data = requests.post(f"{API}/tasks", json=body, headers=HDRS, timeout=60).json()
    task_id = (data.get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"create failed: {data}")
    return task_id


def wait_task(task_id: str, timeout_s: int = 600) -> str:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        data = requests.get(f"{API}/tasks/{task_id}", headers=HDRS, timeout=30).json()
        task = data.get("data") or {}
        if task.get("status") == "success":
            return task["output"][0]["url"]
        if task.get("status") == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task {task_id} failed: {err.get('code')} {err.get('message')}")
        time.sleep(5)
    raise TimeoutError(f"task {task_id} did not finish in {timeout_s}s")


def save_exact(url: str, px: tuple, path: str) -> None:
    # les URL de sortie expirent — téléchargez immédiatement, puis ajustez aux pixels exacts.
    raw = requests.get(url, timeout=120).content
    img = Image.open(BytesIO(raw))
    ImageOps.fit(img, px, Image.LANCZOS).save(path)


if __name__ == "__main__":
    # créez d'abord toutes les tâches : elles s'exécutent en concurrence sur la plateforme
    tasks = {
        name: create_task(s["model"], PROMPT, s["aspect_ratio"], s["resolution"])
        for name, s in SPECS.items()
    }
    for name, task_id in tasks.items():
        url = wait_task(task_id)
        save_exact(url, SPECS[name]["px"], f"{name}.png")
        print(f"{name}: {SPECS[name]['px']} -> {name}.png")

Deux détails méritent d'être repris même si vous réécrivez le reste :

  • Choisissez le palier de résolution de sorte que le côté long soit ≥ la cible. La cible de 2700 pixels d'Etsy dépasse les ~2048 pixels du palier 2K, donc générez en 4K puis réduisez. La réduction avec LANCZOS est visuellement sans perte pour un usage catalogue ; l'agrandissement ne l'est pas.
  • Persistez immédiatement le taskId après création de la tâche. Si votre worker plante, au redémarrage interrogez l'id stocké plutôt que de recréer la tâche — recréer génère (et facture) une seconde image.

Recomposer plutôt une image maîtresse déjà validée

Souvent, vous ne voulez pas sept images générées indépendamment — vous voulez la même image produit déjà validée, recomposée pour chaque canal. C'est le rôle de gpt-image-2/image-to-image : il attend input_urls (un tableau d'URL d'images accessibles publiquement) et prompt, et accepte les mêmes 16 valeurs d'aspect_ratio :

{
  "model": "gpt-image-2/image-to-image",
  "input": {
    "prompt": "Extend the background naturally to fill the new frame; keep the product unchanged and centered",
    "input_urls": ["https://your-cdn.com/hero-shot.png"],
    "aspect_ratio": "9:16"
  }
}

Même cycle de vie de tâche, et à la fin la même étape de pixels exacts. Pour une démonstration complète, voir How to Use gpt-image-2 Image-to-Image via the hiapi API.

Considérations de production

Préférez les callbacks au polling. Côté serveur, passez un callback de premier niveau à la création de la tâche et évitez complètement la boucle de polling :

{
  "model": "gpt-image-2/text-to-image",
  "input": {"prompt": "...", "aspect_ratio": "1:1", "resolution": "2K"},
  "callback": {"url": "https://yourapp.com/hooks/hiapi", "when": "final"}
}

Vous recevrez un seul POST à l'état final. Traitez le callback comme un signal et non comme la source de vérité : refaites un GET /v1/tasks/<id> avant d'agir, et dédupliquez par taskId. Si le callback n'arrive jamais, consultez Why your hiapi task callback isn't firing.

Gestion des erreurs. Un échec d'authentification renvoie 401 permission_denied — vérifiez d'abord l'en-tête Authorization: Bearer sk-.... Un échec de validation renvoie 400 avec error_code: "INVALID_REQUEST", et son message est particulièrement utile : il liste les valeurs exactement autorisées (c'est ainsi que la table des ratios ci-dessus a été vérifiée). Le schéma d'entrée varie selon le modèle — wan2.7-image accepte seed, gpt-image-2 non ; certains modèles rapides rejettent complètement resolution — donc consultez la page de chaque modèle avant de coder en dur des champs.

Maîtrise des coûts. Les prix varient selon le modèle et le palier de résolution. Générez en 1K pendant l'itération sur les prompts, et ne passez à 2K/4K qu'au moment de la version finale — les tarifs actuels par image sont sur la page tarifs.

Lectures complémentaires

Questions fréquentes

Puis-je passer des dimensions exactes en pixels comme 1080×1350 dans la requête ? Non. size, width et height sont rejetés avec un 400 (additional properties ... not allowed). Générez avec l'aspect_ratio correspondant et un palier resolution égal ou supérieur à la cible, puis réduisez localement aux pixels exacts — la ligne Pillow ci-dessus.

Quels réglages utiliser pour l'image principale Amazon ? aspect_ratio: "1:1", resolution: "2K", puis ajustez à votre taille cible (1600×1600 est une valeur par défaut fiable — au-dessus du seuil de zoom de 1000 pixels). L'image principale Amazon exige aussi un fond blanc pur, donc intégrez-le au prompt et validez les sorties avant publication.

Mon ratio cible n'est pas dans la liste (par exemple un format d'annonce 1.91:1). Que faire ? Générez avec le ratio le plus proche plus large ou égal qui couvre entièrement la cible — pour 1.91:1, utilisez 2:1 ou 16:9 — puis recadrez au centre. Le ImageOps.fit du script fait exactement cela : recadrage de l'excédent et redimensionnement en un seul appel.

Comment obtenir une véritable image produit 4K ? Définissez resolution: "4K" sur les deux modèles. wan2.7-image est un choix courant pour les images de style studio 4K ; pour les modèles de prompts, voir le guide e-commerce Wan 2.7.

Les URL des images générées expirent-elles ? Oui — chaque sortie contient expireAt. Téléchargez le fichier et réhébergez-le sur votre propre stockage immédiatement après le succès de la tâche. Ne collez jamais une URL de sortie de tâche dans une fiche produit.

Puis-je générer plusieurs variantes en une seule requête ? Non — ces modèles n'ont pas de paramètre n. Créez une tâche par image ; les tâches s'exécutent en concurrence, donc les traiter en boucle (comme dans le script ci-dessus) est en pratique tout aussi rapide. Sur wan2.7-image, vous pouvez faire varier seed pour obtenir des variantes contrôlées du même prompt.

Articles similaires

Voir tous les articles →

Commencez avec des artefacts IA persistants

Obtenez votre clé API et appelez des modèles d'image, de vidéo et d'audio via une API unique basée sur les tasks.

Lire la documentation de l'API