Source Images Export API
Download the original images your customers uploaded — and any AI images they generated — before rendering.
The Source Images Export API lets you download the original images your customers uploaded (and any AI-generated images they created) while personalising a product — the raw inputs, before Pixel Wrangler renders them into the final print files.
It's the companion to the Artwork Export API:
| API | Returns |
|---|---|
Artwork Export (/api/artwork-export) | The final rendered print files |
Source Images Export (/api/source-images-export) | The original customer uploads + AI images |
Use this when you need the customer's own photo, logo, or AI art — manual retouching, approval workflows, reprints, archiving.
Two ways to download
- From Shopify Admin (no setup) — open any order, use … (more actions) → Download Artwork, then click Download source images. One image downloads directly; multiple images come as a
.zip. Best for one-off, per-order pulls. - API (this page) — for automated or bulk workflows. Uses the same API key as the Artwork Export API.
Endpoint
GET /api/source-images-export
Authentication
Every request must include your API key as a bearer token:
Authorization: Bearer YOUR_API_KEY
This is the same key as the Artwork Export API. To generate one: open the Pixel Wrangler app in Shopify Admin → Settings → Artwork Export API Key → Generate API Key. Treat it like a password; never expose it in client-side code.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
shop | string | Yes | Your Shopify domain (e.g., mystore.myshopify.com) |
orderIds | string | No* | Comma-separated Shopify order GIDs (max 100) |
orderNumbers | string | No* | Comma-separated order numbers, e.g. 1001,1002 (max 100) |
format | string | No | urls (default) or json |
* You must supply at least one of
orderIdsororderNumbers— this API is scoped to specific orders. Unlike the artwork feed, it has no date or cursor mode.
Choosing a format
urls(default, recommended) — returns presigned download links (valid 1 hour) you can fetch directly. This is what you want to actually get the files.json— returns the raw stored URLs plus metadata, without presigning. These point at a private bucket and will not open directly (they return Access Denied). Usejsononly to inspect metadata and counts; useurlsto download.
Response
{
"count": 2,
"expiresInSeconds": 3600,
"files": [
{
"fileName": "customer-photo.png",
"sourceType": "upload",
"origin": "snapshot",
"orderNumbers": ["1001"],
"skus": ["CUST-TEE-M-PK-CT01"],
"lineItemIds": ["gid://shopify/LineItem/111"],
"url": "https://…s3…?X-Amz-Signature=…",
"expiresInSeconds": 3600
}
]
}fileName— suggested filename to save the image as.sourceType— how the image originated:upload(customer-uploaded),ai_image,ai_style_transfer,ai_stylised_text, ornullwhen unknown.origin—snapshot(from the durable order snapshot) orlive. Informational.skus/lineItemIds/orderNumbers— every SKU, line item, and order that references this image (a shared image lists them all). Route the file with these.url— presigned download link (urlsformat only). No auth header needed to fetch it; valid forexpiresInSeconds.
Images are deduped by URL — if the same upload appears on several line items, you get one entry that lists all of them.
Limits & Constraints
| Limit | Value | Notes |
|---|---|---|
| Orders per request | 100 each for orderIds / orderNumbers | Split larger batches |
| Presigned URL expiry | 1 hour | Re-request to mint fresh URLs |
Availability of older orders: every image is captured in the order's design snapshot, so it stays downloadable for the life of that snapshot. For very old orders whose snapshot has been pruned, some source images may no longer be available. Pull what you need promptly after fulfilment.
Error Responses
| Status | Meaning |
|---|---|
200 | Success |
400 | Bad request — missing shop, or no orderIds/orderNumbers filter |
401 | Unauthorized — missing or invalid API key |
404 | No matching orders / no customized items |
500 | Server error |
{ "error": "Description of the error" }Integration Example
Bash
SOURCE_IMAGES_API_KEY="replace-with-your-api-key"
SHOP="mystore.myshopify.com"
BASE="https://your-app-url.com/api/source-images-export"
PAGE=$(curl -sS --oauth2-bearer "${SOURCE_IMAGES_API_KEY}" \
"${BASE}?shop=${SHOP}&orderNumbers=1001,1002&format=urls")
# download each image; skus[0] tells you which product to route it to
printf '%s' "$PAGE" | jq -r '.files[] | [(.skus[0] // "unknown"), .fileName, .url] | @tsv' \
| while IFS=$'\t' read -r sku name url; do
mkdir -p "source-images/${sku}"
curl -sS --fail -o "source-images/${sku}/${name}" "$url"
donePython
import requests
API_KEY = "YOUR_API_KEY"
SHOP = "mystore.myshopify.com"
BASE = "https://your-app-url.com/api/source-images-export"
headers = {"Authorization": f"Bearer {API_KEY}"}
page = requests.get(
BASE,
params={"shop": SHOP, "orderNumbers": "1001,1002", "format": "urls"},
headers=headers,
).json()
for f in page["files"]:
img = requests.get(f["url"]) # presigned — no auth header
# ... write img.content as f["fileName"], routed by f["skus"][0] ...Support
If you hit issues, contact support with:
- Your shop domain
- The full request URL (API key redacted)
- The error response received
- Timestamp of the request