API d'images produit HedaAI
Générez 12 images e-commerce professionnelles (8 images principales + 4 bannières A+) ainsi qu'un texte de fiche produit complet à partir de photos — par programmation, ou directement depuis votre agent IA via MCP.
https://hedaai.com/api/v1 · Miroirs de la documentation pour agents : /developers/api.md · /developers/llms.txtAuthentification
Créez une clé API sur hedaai.com/settings/api-keys (n'importe quel compte convient ; les nouveaux comptes reçoivent un bonus d'inscription de $2.00 ≈ 2 tâches gratuites). La clé complète (hda_live_…) et son secret de webhook (whsec_…) ne sont affichés qu'une seule fois à la création — conservez-les en lieu sûr. Les clés peuvent être nommées, plafonnées en dépense et révoquées à tout moment.
Authorization: Bearer hda_live_...
Les clés sont stockées hachées et restent liées à votre seul compte — une clé API ne peut jamais lire les données d'un autre compte.
GET /v1/account renvoie "mode": "sandbox_watermarked"). Votre premier paiement retire automatiquement les filigranes de tous les produits générés auparavant.Plafonds de dépense : chaque clé possède un spend_cap_cents optionnel (par défaut : illimité). Une fois atteint, la création de tâche échoue avec spend_cap_exceeded (403).
Enveloppe de réponse
{ "status": 200, "code": 200, "message": "", "data": { … } }
Les erreurs ajoutent un error_code pour un aiguillage programmatique. Erreurs de transport vs échecs de tâche : un HTTP 4xx/5xx signifie que la requête a échoué. Une tâche qui échoue pendant la génération n'est pas une erreur HTTP — le polling renvoie 200 avec status: "failed" et un champ error, et vous n'êtes pas facturé.
Démarrage rapide
# 1. Créer une tâche
curl -X POST https://hedaai.com/api/v1/tasks \
-H "Authorization: Bearer $HEDAAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-12345-attempt-1" \
-d '{
"product_name": "stainless steel insulated water bottle",
"images": ["https://your-cdn.example.com/bottle-front.jpg"],
"aspect_ratio": "1:1",
"category": "insulated water bottle 750ml",
"target_market": "amazon_us"
}'
# → data.task_id = "3f8a…", data.status = "queued"
# 2. Interroger toutes les 15–30s jusqu'à l'état terminal
curl -H "Authorization: Bearer $HEDAAI_API_KEY" https://hedaai.com/api/v1/tasks/3f8a…
# → data.status = "succeeded", data.product_id = "9c1b…"
# 3. Récupérer le produit terminé (12 URL d'images + texte de fiche)
curl -H "Authorization: Bearer $HEDAAI_API_KEY" https://hedaai.com/api/v1/products/9c1b…
POST/v1/tasks
Crée une tâche de génération. En-tête optionnel : Idempotency-Key (≤64 caractères, voir plus bas).
| Champ | Type | Requis | Notes |
|---|---|---|---|
product_name | string | oui | Nom court du produit. Signal d'ancrage fort — soyez précis. |
images | string[1–8] | oui | URL de photos (http/https publiques, ≤15MB chacune) et/ou base64 / data-URI. Des photos multi-angles améliorent la fidélité. |
aspect_ratio | string | oui | 1:1, 2:3, 3:2, 3:4, 4:3, 9:16, 16:9. Les images principales Amazon utilisent le 1:1. |
category | string | non | Catégorie concrète, ex. « filtre de rechange pour aspirateur ». Recommandé. |
brand_name | string | non | Alimente l'imagerie de récit de marque et le texte de fiche. |
key_features | string[≤10] | non | Arguments de vente à afficher impérativement. |
specs | object | non | {material, colorway, key_components[], usage_context, use_scenarios[], dimensions[], scale}. Recommandé — l'API n'a pas d'étape de relecture interactive, l'ancrage vient de ce que vous envoyez. |
target_market | string | non | amazon_us (par défaut) · shopify · ebay |
copy_language | string | non | Locale du texte de fiche (en-US, de-DE, ja-JP, …). Par défaut selon le marché cible. |
aplus_format | string | non | banner (16:9, par défaut) · aplus_3_4 · aplus_9_16 · standard_aplus/premium (Amazon uniquement) |
no_human_models | bool | non | true = aucune personne sur les images. |
supplementary_text | string ≤5000 | non | Spécifications en texte libre / extraits de notice à lire par l'IA. |
callback_url | string | non | Webhook pour l'état terminal (Webhooks). |
Renvoie un objet task :
{
"task_id": "3f8a…", "status": "queued", "progress": 0,
"queue_position": 2, "eta_seconds": 840, "cost_cents": 0,
"created_at": "2026-07-17T08:00:00Z",
"urls": { "get": "/api/v1/tasks/3f8a…", "cancel": "/api/v1/tasks/3f8a…/cancel" }
}
GET/v1/tasks/{task_id}
Cycle de vie du statut : queued → processing → succeeded | partial_failed | failed | canceled.
- succeeded — les 12 images sont prêtes ;
product_idrenseigné ;cost_cents: 100facturés. - partial_failed — certaines images ont échoué ; le produit contenant les images réussies est tout de même enregistré ; non facturé.
- failed / canceled — non facturé ;
erroren explique la raison.
Interrogez toutes les 15–30 secondes. queue_position / eta_seconds sont renseignés tant que la tâche est en file.
POST/v1/tasks/{task_id}/cancel
Annule une tâche. L'annulation est gratuite tant que la tâche est en file ; les tâches déjà terminées ne sont pas affectées (idempotent).
GET/v1/products/{product_id}
{
"product_id": "9c1b…", "name": "stainless steel insulated water bottle",
"target_market": "amazon_us", "aspect_ratio": "1:1", "watermarked": false,
"listing_copy": {
"title": "…", "bullet_points": ["…","…","…","…","…"], "description": "…",
"search_terms": "…", "meta_title": "…", "meta_description": "…", "language": "en"
},
"images": [
{ "slice_id": "M1", "section": "main", "url": "https://images.hedaai.com/…",
"url_2k": "https://images.hedaai.com/…", "width": 2048, "height": 2048, "sort_order": 1 }
],
"created_at": "2026-07-17T08:11:32Z"
}
M1–M8sont les 8 images principales,A1–A4les bannières A+.url_2kapparaît pour les comptes payants une fois l'upscale 2K asynchrone terminé (images principales uniquement) — il peut arriver quelques minutes aprèssucceeded.- Juste après
succeeded, une ligne d'image peut rester brièvement en attente — relancez la requête quelques secondes plus tard si vous voyez moins de 12 images. - Les URL sont permanentes (servies depuis notre CDN) ; le hotlinking et la copie sont tous deux autorisés.
GET/v1/account
{
"balance_cents": 1250, "paid_balance_cents": 1000, "bonus_balance_cents": 250,
"has_paid": true, "mode": "live", "price_per_task_cents": 100,
"key": { "name": "prod-integration", "key_prefix": "hda_live_ab12…cd34",
"spend_cap_cents": null, "spent_cents": 700 }
}
Idempotence
Envoyez un en-tête Idempotency-Key (≤64 caractères) sur POST /v1/tasks. Réessayer avec la même clé et le même corps renvoie la tâche d'origine au lieu d'en créer (et d'en facturer) une seconde. La même clé avec un corps différent renvoie 409 idempotency_conflict. Fortement recommandé pour les agents et l'automatisation — les reprises réseau deviennent sûres contre la double facturation.
Webhooks
Définissez callback_url à la création de la tâche pour recevoir un POST à l'état terminal. Événements : task.succeeded, task.partial_failed, task.failed, task.canceled.
{ "id": "evt_…", "type": "task.succeeded", "created_at": "2026-07-17T08:11:35Z",
"data": { /* objet task — même forme que GET /v1/tasks/{id} */ } }
Les signatures suivent la spécification Standard Webhooks — en-têtes webhook-id, webhook-timestamp, webhook-signature: v1,<base64>. Vérifiez avec le webhook_secret de votre clé :
import hmac, hashlib, base64
def verify(secret, msg_id, timestamp, body: bytes, signature_header):
key = base64.b64decode(secret.removeprefix("whsec_"))
expected = base64.b64encode(hmac.new(key, f"{msg_id}.{timestamp}.".encode() + body,
hashlib.sha256).digest()).decode()
return any(hmac.compare_digest(expected, s.split(",", 1)[1])
for s in signature_header.split() if s.startswith("v1,"))
Répondez rapidement avec n'importe quel 2xx (traitez le travail lourd en asynchrone). Livraison : une tentative immédiate, des reprises après 3s / 6s / 12s, puis marquage en échec (le polling reste disponible). Rejetez les horodatages périmés (>5 min) et dédupliquez par id. callback_url doit être un endpoint http(s) public — les adresses privées/internes sont rejetées.
Limites de débit & concurrence
| Limite | Valeur | Dépassement |
|---|---|---|
| Requêtes par clé | 120 / min (tous les endpoints) | 429 rate_limited — consultez les en-têtes RateLimit-Limit / -Remaining / -Reset |
| Tâches en cours par clé | 2 (queued + processing) | 429 concurrency_limit — attendez la fin d'une tâche |
| Capacité API de la plateforme | dynamique | 429 api_capacity — réessayez dans quelques minutes |
La génération est lourde (13–20 appels d'images IA par tâche) : le débit est donc régi par les créneaux de tâches en cours plutôt que par le rythme des requêtes. Besoin de plus de tâches simultanées ? Contactez-nous.
Erreurs
| error_code | HTTP | Signification |
|---|---|---|
bad_request | 400 | Paramètres invalides — le message identifie le champ (ex. images[2]: image download failed with HTTP 403). |
unauthorized | 401 | Clé API manquante/invalide, ou clé révoquée. |
insufficient_credits | 402 | Solde trop faible ; data.balance_cents est inclus. |
spend_cap_exceeded | 403 | Le plafond de dépense de cette clé est épuisé. |
account_disabled / email_not_verified / email_bounced | 403 | Restrictions au niveau du compte. |
not_found | 404 | La tâche/le produit n'existe pas ou appartient à un autre compte. |
idempotency_conflict | 409 | Même Idempotency-Key, corps différent. |
concurrency_limit / api_capacity / rate_limited | 429 | Voir les limites. |
generation_failed / internal_error | 500 | Échec côté serveur ; réessai sans risque avec une clé d'idempotence. |
Exemples de code
Le flux complet — créer une tâche, interroger jusqu'à l'état terminal, récupérer le produit terminé — dans le langage de votre choix.
API=https://hedaai.com/api/v1
# 1. Créer une tâche
TASK_ID=$(curl -sS -X POST "$API/tasks" \
-H "Authorization: Bearer $HEDAAI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: sku-8842-v1" \
-d '{"product_name":"stainless steel insulated water bottle",
"images":["https://your-cdn.example.com/bottle.jpg"],
"aspect_ratio":"1:1"}' | jq -r .data.task_id)
# 2. Interroger jusqu'à l'état terminal
while :; do
TASK=$(curl -sS -H "Authorization: Bearer $HEDAAI_API_KEY" "$API/tasks/$TASK_ID")
STATUS=$(echo "$TASK" | jq -r .data.status)
[ "$STATUS" = "queued" ] || [ "$STATUS" = "processing" ] || break
sleep 20
done
# 3. Récupérer images + texte de fiche
if [ "$STATUS" = "succeeded" ]; then
PRODUCT_ID=$(echo "$TASK" | jq -r .data.product_id)
curl -sS -H "Authorization: Bearer $HEDAAI_API_KEY" "$API/products/$PRODUCT_ID" \
| jq -r '.data.images[].url, .data.listing_copy.title'
fi
import time, requests
API = "https://hedaai.com/api/v1"
H = {"Authorization": "Bearer hda_live_..."}
# 1. Créer une tâche
task = requests.post(f"{API}/tasks",
headers={**H, "Idempotency-Key": "sku-8842-v1"},
json={"product_name": "stainless steel insulated water bottle",
"images": ["https://your-cdn.example.com/bottle.jpg"],
"aspect_ratio": "1:1"}).json()["data"]
# 2. Interroger jusqu'à l'état terminal
while task["status"] in ("queued", "processing"):
time.sleep(20)
task = requests.get(f"{API}/tasks/{task['task_id']}", headers=H).json()["data"]
# 3. Récupérer images + texte de fiche
if task["status"] == "succeeded":
product = requests.get(f"{API}/products/{task['product_id']}", headers=H).json()["data"]
print([img["url"] for img in product["images"]])
print(product["listing_copy"]["title"])
const API = "https://hedaai.com/api/v1";
const H = { Authorization: "Bearer hda_live_...", "Content-Type": "application/json" };
// 1. Créer une tâche
let { data: task } = await (await fetch(`${API}/tasks`, {
method: "POST",
headers: { ...H, "Idempotency-Key": "sku-8842-v1" },
body: JSON.stringify({
product_name: "stainless steel insulated water bottle",
images: ["https://your-cdn.example.com/bottle.jpg"],
aspect_ratio: "1:1",
}),
})).json();
// 2. Interroger jusqu'à l'état terminal
while (["queued", "processing"].includes(task.status)) {
await new Promise(r => setTimeout(r, 20000));
({ data: task } = await (await fetch(`${API}/tasks/${task.task_id}`, { headers: H })).json());
}
// 3. Récupérer images + texte de fiche
if (task.status === "succeeded") {
const { data: product } = await (await fetch(`${API}/products/${task.product_id}`, { headers: H })).json();
console.log(product.images.map(i => i.url), product.listing_copy.title);
}
package main
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"time"
)
const api = "https://hedaai.com/api/v1"
type envelope struct {
Data struct {
TaskID string `json:"task_id"`
Status string `json:"status"`
ProductID string `json:"product_id"`
Images []struct {
URL string `json:"url"`
} `json:"images"`
ListingCopy struct {
Title string `json:"title"`
} `json:"listing_copy"`
} `json:"data"`
}
func call(method, url string, body []byte, extra map[string]string) (envelope, error) {
var out envelope
var rdr *bytes.Reader
if body != nil {
rdr = bytes.NewReader(body)
} else {
rdr = bytes.NewReader(nil)
}
req, err := http.NewRequest(method, url, rdr)
if err != nil {
return out, err
}
req.Header.Set("Authorization", "Bearer hda_live_...")
req.Header.Set("Content-Type", "application/json")
for k, v := range extra {
req.Header.Set(k, v)
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return out, err
}
defer resp.Body.Close()
return out, json.NewDecoder(resp.Body).Decode(&out)
}
func main() {
// 1. Créer une tâche
payload, _ := json.Marshal(map[string]any{
"product_name": "stainless steel insulated water bottle",
"images": []string{"https://your-cdn.example.com/bottle.jpg"},
"aspect_ratio": "1:1",
})
task, err := call("POST", api+"/tasks", payload,
map[string]string{"Idempotency-Key": "sku-8842-v1"})
if err != nil {
panic(err)
}
// 2. Interroger jusqu'à l'état terminal
for task.Data.Status == "queued" || task.Data.Status == "processing" {
time.Sleep(20 * time.Second)
if task, err = call("GET", api+"/tasks/"+task.Data.TaskID, nil, nil); err != nil {
panic(err)
}
}
// 3. Récupérer images + texte de fiche
if task.Data.Status == "succeeded" {
product, err := call("GET", api+"/products/"+task.Data.ProductID, nil, nil)
if err != nil {
panic(err)
}
for _, img := range product.Data.Images {
fmt.Println(img.URL)
}
fmt.Println(product.Data.ListingCopy.Title)
}
}
import java.net.URI;
import java.net.http.*;
import java.time.Duration;
import com.fasterxml.jackson.databind.*; // n'importe quelle bibliothèque JSON convient
public class HedaAI {
static final String API = "https://hedaai.com/api/v1";
static final HttpClient CLIENT = HttpClient.newHttpClient();
static final ObjectMapper MAPPER = new ObjectMapper();
static JsonNode call(HttpRequest.Builder b) throws Exception {
HttpRequest req = b.header("Authorization", "Bearer hda_live_...")
.header("Content-Type", "application/json")
.build();
String body = CLIENT.send(req, HttpResponse.BodyHandlers.ofString()).body();
return MAPPER.readTree(body).path("data");
}
public static void main(String[] args) throws Exception {
// 1. Créer une tâche
JsonNode task = call(HttpRequest.newBuilder(URI.create(API + "/tasks"))
.header("Idempotency-Key", "sku-8842-v1")
.POST(HttpRequest.BodyPublishers.ofString("""
{"product_name":"stainless steel insulated water bottle",
"images":["https://your-cdn.example.com/bottle.jpg"],
"aspect_ratio":"1:1"}""")));
// 2. Interroger jusqu'à l'état terminal
String status = task.path("status").asText();
while (status.equals("queued") || status.equals("processing")) {
Thread.sleep(Duration.ofSeconds(20));
task = call(HttpRequest.newBuilder(
URI.create(API + "/tasks/" + task.path("task_id").asText())).GET());
status = task.path("status").asText();
}
// 3. Récupérer images + texte de fiche
if (status.equals("succeeded")) {
JsonNode product = call(HttpRequest.newBuilder(
URI.create(API + "/products/" + task.path("product_id").asText())).GET());
product.path("images").forEach(img -> System.out.println(img.path("url").asText()));
System.out.println(product.path("listing_copy").path("title").asText());
}
}
}
<?php
$api = "https://hedaai.com/api/v1";
$headers = ["Authorization: Bearer hda_live_...", "Content-Type: application/json"];
function call($method, $url, $headers, $body = null) {
$ch = curl_init($url);
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method, CURLOPT_HTTPHEADER => $headers]);
if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
$res = json_decode(curl_exec($ch), true); curl_close($ch);
return $res["data"];
}
// 1. Créer une tâche
$task = call("POST", "$api/tasks", array_merge($headers, ["Idempotency-Key: sku-8842-v1"]), [
"product_name" => "stainless steel insulated water bottle",
"images" => ["https://your-cdn.example.com/bottle.jpg"],
"aspect_ratio" => "1:1",
]);
// 2. Interroger jusqu'à l'état terminal
while (in_array($task["status"], ["queued", "processing"])) {
sleep(20);
$task = call("GET", "$api/tasks/{$task['task_id']}", $headers);
}
// 3. Récupérer images + texte de fiche
if ($task["status"] === "succeeded") {
$product = call("GET", "$api/products/{$task['product_id']}", $headers);
foreach ($product["images"] as $img) echo $img["url"], "\n";
echo $product["listing_copy"]["title"], "\n";
}
Serveur MCP (pour agents IA)
HedaAI fournit un serveur Model Context Protocol hébergé, pour que les agents génèrent directement des images produit :
- Endpoint :
https://hedaai.com/api/v1/mcp(Streamable HTTP, sans état) - Auth : le même en-tête
Authorization: Bearer hda_live_… - Outils :
create_product_shoot·get_task·get_product·get_balance
claude mcp add --transport http hedaai https://hedaai.com/api/v1/mcp \
--header "Authorization: Bearer $HEDAAI_API_KEY"
{
"mcpServers": {
"hedaai": {
"url": "https://hedaai.com/api/v1/mcp",
"headers": { "Authorization": "Bearer hda_live_..." }
}
}
}
La génération est asynchrone : les agents appellent create_product_shoot (éventuellement avec un idempotency_key), interrogent get_task toutes les 30–60s jusqu'à l'état terminal, puis get_product pour les URL d'images et le texte de fiche. Les clients exigeant OAuth (ex. les connecteurs personnalisés claude.ai) ne sont pas encore pris en charge — utilisez des clients acceptant une clé API comme Claude Code, Cursor ou les SDK d'agents.
Tarifs
| Élément | Prix |
|---|---|
| Shooting produit — 12 images + texte de fiche | $1.00, facturé uniquement en cas de succès |
| Bonus d'inscription | $2.00 (≈ 2 tâches gratuites, filigranées jusqu'au premier paiement) |
| Rechargement du solde | $10–$1000 sur hedaai.com ; ≥$50 +5% de bonus, ≥$100 +10% |
Le solde n'expire jamais. Aucun abonnement. Le prix en vigueur est toujours disponible via GET /v1/account (price_per_task_cents).