Download OpenAPI specification:
Receive print-ready orders from every Picsha storefront, and (roadmap) submit work to Picsha.
Draft v1.0, revised October 15, 2026 — published for partner technical review. Endpoint names, fields, and payloads are stable in intent but open to feedback before the spec is frozen. First published July 28, 2026 for Picsha Retouch and Picsha Books; this revision covers all six Picsha storefronts and the six-state production status every storefront shows its customers.
Picsha is a family of white-label storefronts for photo retailers — Retouch (AI photo
restoration), Prints, Books (AI-designed photo books), Cards and photo calendars,
Posters (AI vintage travel posters) and Gifts (photos on mugs, mousepads, puzzles and more) —
with one landing page per store at yourstore.picsha.com (Picsha Hub) and the same storefronts on
an in-store kiosk. Every storefront already delivers print-ready files to the retailer in its admin.
A retailer whose production runs through Photogize Lab connects each storefront from store admin and every paid order lands in the Lab's harvest queue — Prints as one job per photo, Retouch and Posters as one job per print, Cards as one job per printed side, calendars as thirteen collated jobs, Books as the cover and every page. Live today for every storefront.
storeId — the same slug as the
retailer's storefront subdomains, unchanged when the store serves them from its own domain.lines carry product facts (what was bought and what the finished thing is); outputs carry file
facts (what is in each file). Where an order has several files, line (1-based position in
lines) or side ties a file to what it is for.POST /orders accepts an Idempotency-Key header; retrying with the same key returns the
original result rather than creating a duplicate order.
Part B — the v1 surface. Receive Picsha storefront orders into your production workflow, and report production progress back. Webhook payloads are documented under Webhooks; the pull queue returns the same shape.
Pull-based access to the fulfillment feed, in the same shape as the order.ready webhook.
status filters on the fulfillment status (production) and defaults to received — orders
paid and ready to make that nobody has started. Use for reconciliation, recovery after webhook
downtime, or as a simple polling integration if your platform cannot receive webhooks.
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ Examples: theprintrefineryky The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| status | string (FulfillmentStatus) Default: "received" Enum: "received" "in_production" "ready" "shipped" "delivered" "cancelled" Fulfillment status — production, the status the retailer and the customer see. |
| product | string (Product) Enum: "retouch" "prints" "book" "card" "calendar" "poster" "gift" Only orders from one storefront. |
{- "orders": [
- {
- "event": "order.ready",
- "orderId": "ord_6f39eb74",
- "storeId": "theprintrefineryky",
- "source": "storefront",
- "product": "retouch",
- "createdAt": "2019-08-24T14:15:22Z",
- "fulfillmentStatus": "received",
- "customer": {
- "name": "string",
- "email": "user@example.com"
}, - "delivery": "pickup",
- "shipTo": {
- "name": "string",
- "line1": "string",
- "line2": "string",
- "city": "string",
- "state": "string",
- "postalCode": "string",
- "country": "string",
- "method": "USPS Ground Advantage"
}, - "lines": [
- {
- "type": "retouch",
- "label": "8×10 Print",
- "qty": 1,
- "sizeId": "string",
- "file": "string",
- "options": [
- {
- "type": "Finish",
- "name": "Matte"
}
], - "addons": [
- "colorize"
], - "style": "midcentury",
- "title": "string",
- "subtitle": "string",
- "minInches": 0,
- "widthInches": 0,
- "heightInches": 0,
- "pageCount": 0,
- "format": "flat",
- "flatInches": {
- "width": 0,
- "height": 0
}, - "foldsInches": [
- {
- "axis": "v",
- "at": 0
}
], - "sides": 1,
- "duplex": "long-edge",
- "pages": 1,
- "binding": {
- "style": "wire-o",
- "edge": "top"
}, - "addressed": true,
- "months": 12,
- "startYear": 0,
- "startMonth": 1,
- "span": "August 2027 – July 2028",
- "typeId": "mug-11oz",
- "blank": {
- "widthInches": 0,
- "heightInches": 0,
- "bleedInches": 0,
- "safeInsetInches": 0,
- "wrap": true,
- "diameterInches": 0,
- "seamInches": 0
}, - "press": {
- "mirror": true,
- "includeBleed": true,
- "dpi": 0,
- "format": "png",
- "rotate": 0
}
}
], - "outputs": [
- {
- "type": "image",
- "format": "jpeg",
- "file": "string",
- "line": 1,
- "width": 0,
- "height": 0,
- "dpi": 0,
- "mirrored": true,
- "pages": 0,
- "page": 0,
- "side": 0,
- "sides": [
- {
- "side": 0,
- "page": 0
}
], - "duplex": "long-edge",
- "trimmed": true,
- "mediaInches": {
- "width": 0,
- "height": 0
}, - "trimOriginInches": {
- "x": 0,
- "y": 0
}, - "bleedInches": 0,
- "urlExpiresAt": "2019-08-24T14:15:22Z"
}
]
}
]
}Optional in v1; strongly encouraged. Moves the order's fulfillment status so the retailer and
the customer see production progress in one place. The customer is emailed by the store at
ready (ready for pickup) and shipped, exactly as when the store sets them by hand; shipped
takes a carrier and tracking number, linked on the customer's order page.
problem does not move the customer's timeline: it flags the order for the retailer in admin
with your note and emails the store. Use it for anything a person has to decide. Going backwards
is allowed and recorded; every change appends to the order's history with who made it.
| orderId required | string (OrderId) ^ord_[a-z0-9]+$ Examples: ord_6f39eb74 |
| status required | string Enum: "in_production" "ready" "shipped" "delivered" "problem"
|
object (Shipment) | |
| note | string <= 500 characters Free text for the retailer. Required with |
{- "status": "in_production"
}{- "error": {
- "code": "invalid_asset",
- "message": "string"
}
}Returns a presigned URL to PUT the file bytes to directly. Accepted: JPEG, PNG, TIFF,
HEIC, up to 30 MB. The asset is usable in orders once the PUT completes.
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| filename required | string |
| contentType required | string Enum: "image/jpeg" "image/png" "image/tiff" "image/heic" |
{- "storeId": "theprintrefineryky",
- "filename": "scan-001.jpg",
- "contentType": "image/jpeg"
}{- "assetId": "ast_9f1c2ab4",
- "expiresAt": "2019-08-24T14:15:22Z"
}Picsha fetches the file from sourceUrl at submission time. The URL must be HTTPS and
reachable by Picsha; expiring signed URLs are fine.
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| sourceUrl required | string <uri> |
{- "storeId": "theprintrefineryky",
}{- "assetId": "ast_9f1c2ab4"
}Submits an order for Picsha's AI work. Returns 202 Accepted immediately; processing
is asynchronous. Typical restoration time is about a minute per photo.
product: retouch is the first submission product; book (AI-designed photo books from
20–200 photos) and poster (one photo as a 2:3 vintage travel poster) are documented so partners
can plan for them.
| Idempotency-Key | string <= 64 characters Retrying with the same key returns the original result. |
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| product required | string Enum: "retouch" "book" "poster"
|
| externalRef | string <= 128 characters Your platform's own order/line identifier; echoed on every status response and webhook. |
| assets required | Array of strings (AssetId) [ 1 .. 200 ] items [ items^ast_[a-z0-9]+$ ] |
object Product options. For | |
object (Customer) Included only where the retailer's production workflow requires it. | |
| webhookUrl | string <uri> Overrides your default webhook endpoint for this order. |
{- "storeId": "theprintrefineryky",
- "product": "retouch",
- "externalRef": "string",
- "assets": [
- "ast_9f1c2ab4"
], - "options": {
- "addons": [
- "colorize"
], - "sizeId": "12x12",
- "style": "auto",
- "title": "string",
- "subtitle": "string",
- "palette": "string"
}, - "customer": {
- "name": "string",
- "email": "user@example.com"
},
}{- "orderId": "ord_6f39eb74",
- "status": "received"
}Returns the current state of a submitted order. When status is ready, outputs contains
presigned download URLs valid for 60 minutes; re-fetch for a fresh URL.
Polling is supported, but webhooks are strongly recommended.
| orderId required | string (OrderId) ^ord_[a-z0-9]+$ Examples: ord_6f39eb74 |
{- "orderId": "ord_6f39eb74",
- "externalRef": "string",
- "storeId": "theprintrefineryky",
- "product": "retouch",
- "status": "received",
- "createdAt": "2019-08-24T14:15:22Z",
- "completedAt": "2019-08-24T14:15:22Z",
- "failureReason": "string",
- "outputs": [
- {
- "type": "image",
- "format": "jpeg",
- "file": "string",
- "line": 1,
- "width": 0,
- "height": 0,
- "dpi": 0,
- "mirrored": true,
- "pages": 0,
- "page": 0,
- "side": 0,
- "sides": [
- {
- "side": 0,
- "page": 0
}
], - "duplex": "long-edge",
- "trimmed": true,
- "mediaInches": {
- "width": 0,
- "height": 0
}, - "trimOriginInches": {
- "x": 0,
- "y": 0
}, - "bleedInches": 0,
- "urlExpiresAt": "2019-08-24T14:15:22Z"
}
]
}The feed event. Sent when payment and AI processing are complete. The payload is one
envelope for every storefront: product says which storefront the order came from, lines
say what was bought, outputs are the files. outputs[].downloadUrl is a presigned URL valid
for 60 minutes; fetch the order or the fulfillment queue for a fresh URL at any time.
All webhook deliveries carry X-Picsha-Signature: t=<unix-ts>,v1=<hex> — an HMAC-SHA256
of "<t>.<raw body>" using your webhook secret. Reject deliveries with a bad signature
or a timestamp older than 5 minutes. Deliveries are retried with exponential backoff for
up to 24 hours; respond 2xx to acknowledge.
| event required | string Value: "order.ready" |
| orderId required | string (OrderId) ^ord_[a-z0-9]+$ |
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| source required | string Value: "storefront" |
| product required | string (Product) Enum: "retouch" "prints" "book" "card" "calendar" "poster" "gift" The storefront an order came from (one order comes from one storefront). Part A submission accepts |
| createdAt required | string <date-time> |
| fulfillmentStatus | string (FulfillmentStatus) Enum: "received" "in_production" "ready" "shipped" "delivered" "cancelled" Fulfillment status — production, the status the retailer and the customer see. |
object (Customer) Included only where the retailer's production workflow requires it. | |
| delivery | string Enum: "pickup" "ship" How the customer chose to receive the order. Optional and additive. |
object (ShipTo) The address collected at checkout, flattened to strings, plus the shipping rate the customer chose as | |
required | Array of objects (Line) |
required | Array of objects (Output) |
{- "event": "order.ready",
- "orderId": "ord_7a20c1e9",
- "storeId": "theprintrefineryky",
- "source": "storefront",
- "product": "prints",
- "createdAt": "2026-10-15T15:12:40Z",
- "customer": {
- "name": "J. Smith",
- "email": "customer@example.com"
}, - "delivery": "pickup",
- "lines": [
- {
- "type": "print",
- "label": "4×6 Print",
- "sizeId": "4x6",
- "widthInches": 6,
- "heightInches": 4,
- "qty": 3,
- "file": "IMG_2041.jpg",
- "options": [
- {
- "type": "Finish",
- "name": "Matte"
}
]
}, - {
- "type": "print",
- "label": "8×10 Print",
- "sizeId": "8x10",
- "widthInches": 8,
- "heightInches": 10,
- "qty": 1,
- "file": "IMG_2041.jpg"
}
], - "outputs": [
- {
- "type": "jpeg",
- "line": 1,
- "file": "4x6in/001-IMG_2041.jpg",
- "width": 1800,
- "height": 1200,
- "dpi": 300,
- "urlExpiresAt": "2026-10-15T16:12:40Z"
}, - {
- "type": "jpeg",
- "line": 2,
- "file": "8x10in/002-IMG_2041.jpg",
- "width": 2400,
- "height": 3000,
- "dpi": 300,
- "urlExpiresAt": "2026-10-15T16:12:40Z"
}
]
}Sent when the store or Picsha cancels a paid order that has already been delivered to the feed,
so you can pull it from production. An order you have already started should be reported back
with problem on the status round-trip.
| event required | string Enum: "order.processing" "order.ready" "order.failed" "order.cancelled" |
| orderId required | string (OrderId) ^ord_[a-z0-9]+$ |
| externalRef | string |
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| product required | string (Product) Enum: "retouch" "prints" "book" "card" "calendar" "poster" "gift" The storefront an order came from (one order comes from one storefront). Part A submission accepts |
| createdAt | string <date-time> |
{- "event": "order.processing",
- "orderId": "ord_6f39eb74",
- "externalRef": "string",
- "storeId": "theprintrefineryky",
- "product": "retouch",
- "createdAt": "2019-08-24T14:15:22Z"
}| event required | string Enum: "order.processing" "order.ready" "order.failed" "order.cancelled" |
| orderId required | string (OrderId) ^ord_[a-z0-9]+$ |
| externalRef | string |
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| product required | string (Product) Enum: "retouch" "prints" "book" "card" "calendar" "poster" "gift" The storefront an order came from (one order comes from one storefront). Part A submission accepts |
| createdAt | string <date-time> |
{- "event": "order.processing",
- "orderId": "ord_6f39eb74",
- "externalRef": "string",
- "storeId": "theprintrefineryky",
- "product": "retouch",
- "createdAt": "2019-08-24T14:15:22Z"
}| event required | string Enum: "order.processing" "order.ready" "order.failed" "order.cancelled" |
| orderId required | string (OrderId) ^ord_[a-z0-9]+$ |
| externalRef | string |
| storeId required | string (StoreId) ^[a-z0-9-]{2,30}$ The retailer's Picsha store identifier — the same slug as every one of their storefront subdomains ( |
| product required | string (Product) Enum: "retouch" "prints" "book" "card" "calendar" "poster" "gift" The storefront an order came from (one order comes from one storefront). Part A submission accepts |
| createdAt | string <date-time> |
| failureReason required | string |
{- "event": "order.processing",
- "orderId": "ord_6f39eb74",
- "externalRef": "string",
- "storeId": "theprintrefineryky",
- "product": "retouch",
- "createdAt": "2019-08-24T14:15:22Z",
- "failureReason": "asset_unreadable"
}