Automating E-Commerce Image Workflows with AI APIs: A Production Architecture Guide
This isn't a tutorial for hobbyists. It's an architecture breakdown for teams running product catalogs at volume.
Here's how to build a fully automated image pipeline that handles everything from raw product shots to marketplace-ready images.
The Problem at Scale
A mid-size e-commerce operation might manage 50,000 SKUs. Each SKU needs:
- Background removed → transparent PNG for compositing
- Lifestyle version → product on scene background
- Upscaled → minimum resolution for marketplace requirements
- Thumbnail → multiple sizes for CDN
Doing this manually, even with fast Photoshop operators, costs significant labor at any meaningful catalog size. Doing it with a simple script hits API rate limits, error handling problems, and infrastructure costs.
Here's a production-grade approach.
Architecture Overview
Raw uploads (S3) → Queue (SQS/Redis) → Worker pool → Processed images (CDN)
↓
AI API calls
(background, upscale, etc.)
The Worker
import boto3, requests, redis, json, time, logging
from concurrent.futures import ThreadPoolExecutor, as_completed
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
PIXELAPI_KEY = os.environ["PIXELAPI_KEY"]
PIXELAPI_BASE = "https://api.pixelapi.dev/v1"
def call_pixelapi(operation: str, image_url: str, **kwargs) -> str:
headers = {"Authorization": f"Bearer {PIXELAPI_KEY}"}
payload = {"operation": operation, "image_url": image_url, **kwargs}
for attempt in range(3):
try:
r = requests.post(f"{PIXELAPI_BASE}/edit",
headers=headers, json=payload, timeout=60)
r.raise_for_status()
return r.json()["output_url"]
except requests.HTTPError as e:
if e.response.status_code == 429: # Rate limited
time.sleep(2 ** attempt)
elif e.response.status_code in (500, 503):
time.sleep(5)
else:
raise
raise Exception(f"Failed after 3 attempts: {operation} on {image_url}")
def process_sku(sku_id: str, raw_url: str) -> dict:
results = {}
try:
# Step 1: Remove background
logger.info(f"SKU {sku_id}: removing background")
no_bg = call_pixelapi("remove-bg", raw_url)
results["transparent"] = no_bg
# Step 2: Upscale for marketplace requirements
logger.info(f"SKU {sku_id}: upscaling")
upscaled = call_pixelapi("upscale", no_bg, scale=4)
results["upscaled"] = upscaled
# Step 3: Generate lifestyle image
logger.info(f"SKU {sku_id}: generating lifestyle variant")
lifestyle = call_pixelapi("replace-bg", no_bg,
prompt="clean white studio, subtle shadow, professional product photography")
results["lifestyle"] = lifestyle
results["status"] = "success"
except Exception as e:
logger.error(f"SKU {sku_id} failed: {e}")
results["status"] = "failed"
results["error"] = str(e)
return {"sku_id": sku_id, **results}
def process_batch(sku_list: list, concurrency: int = 5) -> list:
with ThreadPoolExecutor(max_workers=concurrency) as executor:
futures = {
executor.submit(process_sku, sku["id"], sku["raw_url"]): sku["id"]
for sku in sku_list
}
results = []
for future in as_completed(futures):
results.append(future.result())
return results
Error Handling and Idempotency
def process_with_checkpoint(sku_list: list, checkpoint_file: str) -> list:
# Load already-processed SKUs
processed = {}
if os.path.exists(checkpoint_file):
with open(checkpoint_file) as f:
processed = json.load(f)
to_process = [s for s in sku_list if s["id"] not in processed]
logger.info(f"{len(to_process)} remaining, {len(processed)} already done")
results = process_batch(to_process)
# Save checkpoint
for r in results:
if r["status"] == "success":
processed[r["sku_id"]] = r
with open(checkpoint_file, "w") as f:
json.dump(processed, f)
return list(processed.values())
Cost Modeling
For 10,000 SKUs needing the full pipeline (bg removal + upscale + lifestyle):
- Background removal: 10 credits × 10,000 = 100,000 credits
- Upscale: 50 credits × 10,000 = 500,000 credits
- Lifestyle background: 10 credits × 10,000 = 100,000 credits
- Total: 700,000 credits
At the Scale plan (300,000 credits), this requires ~2.3 plan purchases. Compare this to manual editing or per-image freelance costs at any reasonable volume.
CDN Integration Pattern
import httpx
async def download_and_store(result_url: str, destination_key: str, s3_client):
"""Download from PixelAPI (24h availability) and store permanently."""
async with httpx.AsyncClient() as client:
response = await client.get(result_url)
s3_client.put_object(
Bucket="your-cdn-bucket",
Key=destination_key,
Body=response.content,
ContentType="image/png"
)
Always download and re-host. PixelAPI URLs are temporary (24h) by design.
Monitoring
def monitor_batch(results: list) -> dict:
total = len(results)
success = sum(1 for r in results if r["status"] == "success")
failed = total - success
return {
"total": total,
"success": success,
"failed": failed,
"success_rate": f"{100*success/total:.1f}%",
"failed_skus": [r["sku_id"] for r in results if r["status"] == "failed"]
}
Getting Started
Start with a batch of 100 test SKUs before running your full catalog. Verify quality, check edge cases (transparent products, white-on-white, reflective surfaces), tune your prompts.
pixelapi.dev — 100 free credits. API docs: api.pixelapi.dev/docs
PixelAPI handles concurrent requests across GPU workers. For large batch jobs, contact support for rate limit adjustments.
Top comments (0)