HedaAI 商品圖 API
從商品照片生成 12 張專業電商圖片(8 張主圖 + 4 張 A+ 橫幅)與完整 listing 文案 — 可用程式呼叫,也可透過 MCP 直接由你的 AI agent 生成。
身分驗證
在 hedaai.com/settings/api-keys 建立 API 金鑰(任何帳戶皆可;新帳戶可獲得 $2.00 註冊贈金 ≈ 2 次免費任務)。完整金鑰(hda_live_…)與其 webhook secret(whsec_…)只在建立時顯示一次 — 請妥善保存。金鑰可命名、設定消費上限,並隨時撤銷。
Authorization: Bearer hda_live_...
金鑰以雜湊形式儲存,且僅綁定你的帳戶 — API 金鑰永遠無法讀取其他帳戶的資料。
GET /v1/account 會回報 "mode": "sandbox_watermarked")。首次付款後,先前已生成的所有商品都會自動移除浮水印。消費上限:每把金鑰都可選擇性設定 spend_cap_cents(預設:無上限)。達到上限後,建立任務會以 spend_cap_exceeded(403)失敗。
回應結構
{ "status": 200, "code": 200, "message": "", "data": { … } }
錯誤會額外帶上 error_code 供程式比對。傳輸錯誤 vs 任務失敗:HTTP 4xx/5xx 表示請求失敗。任務在生成過程中失敗並不是 HTTP 錯誤 — 輪詢會回傳 200,帶有 status: "failed" 與 error 欄位,且不會向你計費。
快速上手
# 1. 建立任務
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. 每 15–30s 輪詢一次直到終態
curl -H "Authorization: Bearer $HEDAAI_API_KEY" https://hedaai.com/api/v1/tasks/3f8a…
# → data.status = "succeeded", data.product_id = "9c1b…"
# 3. 取得完成的商品(12 個圖片URL + listing 文案)
curl -H "Authorization: Bearer $HEDAAI_API_KEY" https://hedaai.com/api/v1/products/9c1b…
POST/v1/tasks
建立生成任務。選用 header:Idempotency-Key(≤64 字元,見下文)。
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
product_name | string | 是 | 簡短的商品名稱。重要的 grounding 訊號 — 請寫得具體。 |
images | string[1–8] | 是 | 照片URL(公開 http/https,每張 ≤15MB)與/或 base64 / data-URI。多角度照片能提升保真度。 |
aspect_ratio | string | 是 | 1:1、2:3、3:2、3:4、4:3、9:16、16:9。Amazon 主圖使用 1:1。 |
category | string | 否 | 具體的品類,例如 "vacuum cleaner replacement filter"。建議填寫。 |
brand_name | string | 否 | 用於品牌故事圖與 listing 文案。 |
key_features | string[≤10] | 否 | 必須呈現的賣點。 |
specs | object | 否 | {material, colorway, key_components[], usage_context, use_scenarios[], dimensions[], scale}。建議填寫 — 此 API 沒有互動式確認步驟,grounding 全部來自你送出的內容。 |
target_market | string | 否 | amazon_us(預設)· shopify · ebay |
copy_language | string | 否 | Listing 文案語系(en-US、de-DE、ja-JP…)。預設依目標市場而定。 |
aplus_format | string | 否 | banner(16:9,預設)· aplus_3_4 · aplus_9_16 · standard_aplus/premium(僅限 Amazon) |
no_human_models | bool | 否 | true = 所有圖片皆不出現人物。 |
supplementary_text | string ≤5000 | 否 | 自由文字的規格/說明書摘錄,供 AI 閱讀。 |
callback_url | string | 否 | 終態狀態的 webhook(Webhooks)。 |
回傳一個 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}
狀態流程:queued → processing → succeeded | partial_failed | failed | canceled。
- succeeded — 12 張圖片全部完成;已設定
product_id;已扣款cost_cents: 100。 - partial_failed — 部分圖片失敗;含成功圖片的商品仍會保存;不計費。
- failed / canceled — 不計費;
error會說明原因。
每 15–30 秒輪詢一次。排隊期間會提供 queue_position / eta_seconds。
POST/v1/tasks/{task_id}/cancel
取消任務。排隊中取消免費;已完成的任務不受影響(冪等)。
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–M8是 8 張主圖,A1–A4是 A+ 橫幅。- 付費帳戶在非同步 2K 超解析完成後會出現
url_2k(僅主圖)— 可能比succeeded晚幾分鐘。 - 剛進入
succeeded時,個別圖片列可能短暫處於 pending — 若看到少於 12 張圖片,請幾秒後重新取得。 - URL是永久的(由我們的 CDN 提供);熱連結與複製使用都沒問題。
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 }
}
冪等性
在 POST /v1/tasks 帶上 Idempotency-Key header(≤64 字元)。以相同金鑰與相同 body 重試會回傳原本的任務,而不會建立(並最終計費)重複任務。相同金鑰搭配不同 body 會回傳 409 idempotency_conflict。強烈建議 agent 與自動化流程使用 — 網路重試便不會重複扣款。
Webhooks
建立任務時設定 callback_url,即可在終態時收到 POST。事件:task.succeeded、task.partial_failed、task.failed、task.canceled。
{ "id": "evt_…", "type": "task.succeeded", "created_at": "2026-07-17T08:11:35Z",
"data": { /* task 物件 — 與 GET /v1/tasks/{id} 結構相同 */ } }
簽章遵循 Standard Webhooks 規範 — headers 為 webhook-id、webhook-timestamp、webhook-signature: v1,<base64>。請用該金鑰的 webhook_secret 驗證:
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,"))
請盡快回應任何 2xx(繁重工作改以非同步處理)。投遞方式:立即嘗試一次,之後於 3s / 6s / 12s 重試,再失敗則標記為失敗(仍可用 polling 取得結果)。請拒絕過期的 timestamp(>5 分鐘)並以 id 去重。callback_url 必須是公開的 http(s) endpoint — 私有/內網位址會被拒絕。
速率限制與並行數
| 限制 | 值 | 超過時 |
|---|---|---|
| 每把金鑰的請求數 | 120 / 分鐘(所有 endpoint) | 429 rate_limited — 請檢查 RateLimit-Limit / -Remaining / -Reset headers |
| 每把金鑰進行中的任務數 | 2(queued + processing) | 429 concurrency_limit — 等待任務完成 |
| 平台 API 容量 | 動態 | 429 api_capacity — 幾分鐘後重試 |
生成相當耗資源(每個任務 13–20 次 AI 圖片呼叫),因此吞吐量取決於進行中的任務名額,而非請求速率。需要更高的並行數?聯絡我們。
錯誤
| error_code | HTTP | 含義 |
|---|---|---|
bad_request | 400 | 參數無效 — 訊息會指出具體欄位(例如 images[2]: image download failed with HTTP 403)。 |
unauthorized | 401 | 缺少/無效的 API 金鑰,或金鑰已撤銷。 |
insufficient_credits | 402 | 餘額不足;回應會含 data.balance_cents。 |
spend_cap_exceeded | 403 | 此金鑰的消費上限已用盡。 |
account_disabled / email_not_verified / email_bounced | 403 | 帳戶層級的限制。 |
not_found | 404 | 任務/商品不存在,或屬於其他帳戶。 |
idempotency_conflict | 409 | 相同的 Idempotency-Key,不同的 body。 |
concurrency_limit / api_capacity / rate_limited | 429 | 參見速率限制。 |
generation_failed / internal_error | 500 | 伺服器端失敗;可搭配冪等金鑰安全重試。 |
程式碼範例
完整流程 — 建立任務、輪詢至終態、取得完成的商品 — 以你選擇的語言呈現。
API=https://hedaai.com/api/v1
# 1. 建立任務
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. 輪詢直到終態
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. 取得圖片 + listing 文案
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. 建立任務
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. 輪詢直到終態
while task["status"] in ("queued", "processing"):
time.sleep(20)
task = requests.get(f"{API}/tasks/{task['task_id']}", headers=H).json()["data"]
# 3. 取得圖片 + listing 文案
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. 建立任務
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. 輪詢直到終態
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. 取得圖片 + listing 文案
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. 建立任務
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. 輪詢直到終態
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. 取得圖片 + listing 文案
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.*; // 任何 JSON 函式庫皆可
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. 建立任務
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. 輪詢直到終態
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. 取得圖片 + listing 文案
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. 建立任務
$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. 輪詢直到終態
while (in_array($task["status"], ["queued", "processing"])) {
sleep(20);
$task = call("GET", "$api/tasks/{$task['task_id']}", $headers);
}
// 3. 取得圖片 + listing 文案
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";
}
MCP 伺服器(給 AI agent)
HedaAI 提供託管的 Model Context Protocol 伺服器,讓 agent 可以直接生成商品圖:
- Endpoint:
https://hedaai.com/api/v1/mcp(Streamable HTTP,無狀態) - 驗證:使用同一個
Authorization: Bearer hda_live_…header - 工具:
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_..." }
}
}
}
生成是非同步的:agent 呼叫 create_product_shoot(可選擇帶上 idempotency_key),每 30–60s 輪詢 get_task 直到終態,再以 get_product 取得圖片URL與 listing 文案。目前尚不支援必須使用 OAuth 的用戶端(例如 claude.ai 自訂連接器)— 請改用支援 API 金鑰的用戶端,例如 Claude Code、Cursor 或 agent SDK。
定價
| 項目 | 價格 |
|---|---|
| 商品拍攝 — 12 張圖片 + listing 文案 | $1.00,僅在成功時計費 |
| 註冊贈金 | $2.00(≈ 2 次免費任務,首次付款前帶浮水印) |
| 餘額儲值 | 於 hedaai.com 儲值 $10–$1000;≥$50 +5% 贈金,≥$100 +10% |
餘額永不過期。無訂閱制。即時價格隨時可透過 GET /v1/account 取得(price_per_task_cents)。