Developers api.md llms.txt
🌐 English
Get API key

HedaAI Product Images API

Generate 12 professional e-commerce images (8 main images + 4 A+ banners) plus complete listing copy from product photos — programmatically, or straight from your AI agent via MCP.

$1.00 / productcharged only on success
~10 minutesasynchronous: create → poll → fetch
Permanent storageresults live in your account, no URL expiry
MCP built inhosted server for AI agents
Base URL: https://hedaai.com/api/v1  ·  Docs mirrors for agents: /developers/api.md · /developers/llms.txt

Authentication

Create an API key at hedaai.com/settings/api-keys (any account works; new accounts get a $2.00 signup bonus ≈ 2 free tasks). The full key (hda_live_…) and its webhook secret (whsec_…) are shown once at creation — store them securely. Keys can be named, spend-capped, and revoked at any time.

Authorization: Bearer hda_live_...

Keys are stored hashed and are bound to your account only — an API key can never read another account's data.

Sandbox mode (free testing): until your account has made a real payment, generated images carry a watermark and no 2K upscale — everything else behaves identically (GET /v1/account reports "mode": "sandbox_watermarked"). Your first payment removes watermarks from all previously generated products automatically.

Spend caps: each key has an optional spend_cap_cents (default: unlimited). When reached, task creation fails with spend_cap_exceeded (403).

Response envelope

{ "status": 200, "code": 200, "message": "", "data": { … } }

Errors add an error_code for programmatic matching. Transport errors vs task failures: HTTP 4xx/5xx means the request failed. A task that fails during generation is not an HTTP error — polling returns 200 with status: "failed" and an error field, and you are not charged.

Quickstart

# 1. Create a task
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. Poll every 15–30s until terminal
curl -H "Authorization: Bearer $HEDAAI_API_KEY" https://hedaai.com/api/v1/tasks/3f8a…
# → data.status = "succeeded", data.product_id = "9c1b…"

# 3. Fetch the finished product (12 image URLs + listing copy)
curl -H "Authorization: Bearer $HEDAAI_API_KEY" https://hedaai.com/api/v1/products/9c1b…

POST/v1/tasks

Creates a generation task. Optional header: Idempotency-Key (≤64 chars, see below).

FieldTypeRequiredNotes
product_namestringyesShort product name. Strong grounding signal — be specific.
imagesstring[1–8]yesPhoto URLs (public http/https, ≤15MB each) and/or base64 / data-URIs. Multi-angle photos improve fidelity.
aspect_ratiostringyes1:1, 2:3, 3:2, 3:4, 4:3, 9:16, 16:9. Amazon main images use 1:1.
categorystringnoConcrete category, e.g. "vacuum cleaner replacement filter". Recommended.
brand_namestringnoFeeds brand-story imagery and listing copy.
key_featuresstring[≤10]noMust-show selling points.
specsobjectno{material, colorway, key_components[], usage_context, use_scenarios[], dimensions[], scale}. Recommended — the API has no interactive review step, grounding comes from what you send.
target_marketstringnoamazon_us (default) · shopify · ebay
copy_languagestringnoListing copy locale (en-US, de-DE, ja-JP, …). Defaults from target market.
aplus_formatstringnobanner (16:9, default) · aplus_3_4 · aplus_9_16 · standard_aplus/premium (Amazon only)
no_human_modelsboolnotrue = no people in any image.
supplementary_textstring ≤5000noFree-text specs / manual excerpts for the AI to read.
callback_urlstringnoWebhook for terminal status (Webhooks).

Returns a task object:

{
  "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}

Status lifecycle: queuedprocessingsucceeded | partial_failed | failed | canceled.

Poll every 15–30 seconds. queue_position / eta_seconds are populated while queued.

POST/v1/tasks/{task_id}/cancel

Cancels a task. Free while queued; already-finished tasks are unaffected (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"
}

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 }
}

Idempotency

Pass an Idempotency-Key header (≤64 chars) on POST /v1/tasks. Retrying with the same key and same body returns the original task instead of creating (and eventually charging) a duplicate. The same key with a different body returns 409 idempotency_conflict. Strongly recommended for agents and automation — network retries become double-spend-safe.

Webhooks

Set callback_url on task creation to receive a POST at terminal status. Events: task.succeeded, task.partial_failed, task.failed, task.canceled.

{ "id": "evt_…", "type": "task.succeeded", "created_at": "2026-07-17T08:11:35Z",
  "data": { /* task object — same shape as GET /v1/tasks/{id} */ } }

Signatures follow the Standard Webhooks spec — headers webhook-id, webhook-timestamp, webhook-signature: v1,<base64>. Verify with your key's 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,"))

Respond with any 2xx quickly (do heavy work async). Delivery: one immediate attempt, retries after 3s / 6s / 12s, then marked failed (polling still works). Reject stale timestamps (>5 min) and de-duplicate by id. callback_url must be a public http(s) endpoint — private/internal addresses are rejected.

Rate limits & concurrency

LimitValueOn exceed
Requests per key120 / min (all endpoints)429 rate_limited — check RateLimit-Limit / -Remaining / -Reset headers
In-flight tasks per key2 (queued + processing)429 concurrency_limit — wait for a task to finish
Platform API capacitydynamic429 api_capacity — retry in a few minutes

Generation is heavy (13–20 AI image calls per task), so throughput is governed by in-flight task slots rather than request rate. Need more concurrency? Contact us.

Errors

error_codeHTTPMeaning
bad_request400Invalid parameters — message pinpoints the field (e.g. images[2]: image download failed with HTTP 403).
unauthorized401Missing/invalid API key, or key revoked.
insufficient_credits402Balance too low; data.balance_cents included.
spend_cap_exceeded403This key's spend cap is exhausted.
account_disabled / email_not_verified / email_bounced403Account-level gates.
not_found404Task/product doesn't exist or belongs to another account.
idempotency_conflict409Same Idempotency-Key, different body.
concurrency_limit / api_capacity / rate_limited429See limits.
generation_failed / internal_error500Server-side failure; safe to retry with an idempotency key.

Code examples

The full flow — create a task, poll until terminal, fetch the finished product — in the language of your choice.

API=https://hedaai.com/api/v1

# 1. Create a task
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. Poll until 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. Fetch images + listing copy
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

MCP server (for AI agents)

HedaAI ships a hosted Model Context Protocol server so agents can generate product images directly:

claude mcp add --transport http hedaai https://hedaai.com/api/v1/mcp \
  --header "Authorization: Bearer $HEDAAI_API_KEY"

Generation is asynchronous: agents call create_product_shoot (optionally with an idempotency_key), poll get_task every 30–60s until terminal, then get_product for image URLs and listing copy. Clients that require OAuth (e.g. claude.ai custom connectors) are not supported yet — use API-key-capable clients such as Claude Code, Cursor, or agent SDKs.

Pricing

ItemPrice
Product shoot — 12 images + listing copy$1.00, charged on success only
Signup bonus$2.00 (≈ 2 free tasks, watermarked until first payment)
Balance top-up$10–$1000 at hedaai.com; ≥$50 +5% bonus, ≥$100 +10%

Balance never expires. No subscription. The live price is always available at GET /v1/account (price_per_task_cents).