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')const res = await fetch("https://api.photta.app/api/v1/ghost-mannequin", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({
"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"
}),
});
const { data } = await res.json(); // data.id, data.statusimport os, requests
res = requests.post(
"https://api.photta.app/api/v1/ghost-mannequin",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"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"
},
)
data = res.json()["data"] # data["id"], data["status"]How it works
Nightly run, catalog-wide
Five pieces you need for an automation that runs unattended.
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.
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.
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.
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.
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.
Related pages
Reference
Capabilities
Ghost mannequin API for hollow-man product photos
AI ghost mannequin endpoint. Remove the mannequin from a garment photo and preserve interior detail. 3D or flat-lay, batch processing, 4 credits at 2K.
ReadQuickstart
First Photta image in under five minutes.
Sign up, generate an API key, run your first cURL call, poll until it completes, persist the result. Five steps, documented end-to-end.
ReadLanguages
Python walkthrough
Read
Every figure on this page comes from the Photta API docs · checked
Ship catalog-scale ghost mannequin tonight
Three Python functions, one cron, 50K photos. Grab an API key and point it at your catalog.