Build · Ghost Mannequin Automation

Automate ghost mannequin extraction for your catalog

In one sentence

Pull the catalog delta since your last run, POST a product_images array (each item an image URL plus optional back_image) with one style to /api/v1/ghost-mannequin/batch, poll the batch ID every 3 seconds until every item is completed or failed, then update each product row with its output_url. Concurrent batches are capped per plan.

  • Credits: 4 credits at 2K · 5 credits at 4K
  • Typical time: 1.5–4 min
  • Processing: async, polling

Every figure on this page comes from the Photta API docs · checked

Strip the mannequin out of every PDP photo without touching a designer. Photta's ghost-mannequin endpoint batches naturally — a nightly cron turns a 50K-SKU feed into an invisible-mannequin catalog in hours, not weeks.

RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/ghost-mannequin \
  -H "Authorization: Bearer $PHOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "product_image": "https://cdn.yourstore.com/products/jacket-front.jpg",
  "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
  "image_side": "front",
  "angle": "side",
  "style": "3d",
  "background_color": "white",
  "resolution": "2K",
  "aspect_ratio": "3:4",
  "user_instruction": "closed front, cream interior lining",
  "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')

How it works

Nightly run, catalog-wide

Five pieces you need for an automation that runs unattended.

  1. Step 1

    Map your catalog

    Know which product rows need a ghost mannequin image, which already have one, and which have gated categories. Store a last_photographed_at timestamp so the nightly job only processes the delta.

  2. Step 2

    Pick 3D or flat-lay per category

    `3d` for garments that need volume — outerwear, denim, tailored pieces. `flat_lay` for accessories and knitwear that photograph better laid flat. Store the style per product category so the batch builder picks the right one without hand-tuning.

  3. Step 3

    Batch-submit the delta

    POST /api/v1/ghost-mannequin/batch with a product_images array — each item carries image, optional back_image and image_side — plus one style, background_color and resolution for the whole batch. Keep your own map from array position to product ID; the response returns one generation ID per item in the same order.

  4. Step 4

    Poll the parent batch

    The batch endpoint returns aggregate counters (total, processing, completed, failed). Poll every 3 seconds until completed + failed equals total. Photta processes items in parallel inside the batch, so you don't need to poll individual generations.

  5. Step 5

    Persist into your database

    Iterate status.data.items in order — the batch keeps your array order — and update each product row with its output_url. Log failures — they almost always point to a bad source photo in your feed, which you can fix and resubmit on the next run.

Three steps in Python

Delta extract, batch submit, parent poll — the minimum viable catalog automation.

from datetime import datetime, timedelta

yesterday = datetime.utcnow() - timedelta(days=1)
rows = db.execute(
    "SELECT id, source_image_url FROM products WHERE updated_at > %s",
    (yesterday,),
).fetchall()
import os, requests

res = requests.post(
    "https://api.photta.app/api/v1/ghost-mannequin/batch",
    headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
    json={
      "product_images": [
        {
          "image": "https://cdn.yourstore.com/products/jacket-front.jpg",
          "back_image": "https://cdn.yourstore.com/products/jacket-back.jpg",
          "image_side": "front"
        },
        {
          "image": "https://cdn.yourstore.com/products/shirt-front.jpg",
          "image_side": "front"
        },
        {
          "image": "https://cdn.yourstore.com/products/trousers-front.jpg",
          "image_side": "front"
        }
      ],
      "style": "3d",
      "background_color": "white",
      "resolution": "2K",
      "aspect_ratio": "3:4",
      "user_instruction": "closed front, buttoned up",
      "brand_label_id": "7cc9f988-068b-44cd-8004-22f486b10e67"
    },
)
data = res.json()["data"]  # data["id"], data["status"]
import os, time, requests

BASE = "https://api.photta.app/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"}
# data["items"] comes back in the order of the product_images you submitted.
batch_id = data["batch_id"]
for _ in range(240):  # 240 × 3s = 12 minutes
    status = requests.get(f"{BASE}/ghost-mannequin/batch/{batch_id}", headers=HEADERS).json()["data"]
    if status["completed"] + status["failed"] == status["total"]:
        break
    time.sleep(3)

for row, item in zip(rows, status["items"]):
    if item["status"] == "completed":
        db.execute(
            "UPDATE products SET ghost_image_url = %s WHERE id = %s",
            (item["output_url"], row.id),
        )

Questions developers ask

Running ghost mannequin at catalog scale

How big can a single batch be?

The batch endpoint accepts up to a few hundred items per call per the docs. For a 50K-SKU nightly run, chunk the delta into batches of 100–200 and fire them sequentially so you stay comfortably under the plan rate limit.

Can a batch mix 3D and flat-lay?

Yes — style is a per-item field, so a single batch can contain both. In practice most teams split by category anyway because the downstream persistence logic is simpler when every row in a batch lands in the same database column.

What happens to failed items?

Failed items in a batch refund their credits automatically and carry an error_code + error_message in the final item payload. Log the failures and retry them the next night after your team has a chance to fix the source photo or mark the row as permanently-bad-input.

How do I map results back to my product IDs?

Keep your own map from array position to product ID when you submit: the batch response returns one generation ID per item in the same order as product_images, and the batch status lists items in that order too.

Can I schedule this as a daily cron?

Yes — a simple daily cron that pulls the last-24-hour delta, chunks it, submits batches, and writes results into your database is a load-bearing pattern for catalog-scale teams. Keep the runner idempotent so a failed night can be replayed safely.

Ship catalog-scale ghost mannequin tonight

Three Python functions, one cron, 50K photos. Grab an API key and point it at your catalog.