Skip to content

Extract a background, model, product and shot recipe from one PDP photograph

POST
/v1/pdp-extractions
curl --request POST \
--url https://example.com/v1/pdp-extractions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{ "pdp_image_public_id": "01JUPLOAD0000000000000000A", "product_name": "Emerald Silk Saree" }'

Dispatch a PDP extraction: read one product-detail-page photograph back into the four things that made it — an empty background plate, the person as a catalog model, the garment as a product shot, and the photography recipe (camera, light, pose, styling). All four land owned by your client and are immediately reusable in POST /v1/catalog-shots, which is the same journey in reverse.

Pass the asset_id from POST /v1/uploads. Returns 202 with a job_id; poll GET /v1/jobs/{job_id}. Partial success is normal: a flat-lay has no person, so that arm produces nothing while the rest still land — the terminal event carries one artifact per entity plus a failures entry naming every arm that produced nothing. Charged once at dispatch and refunded only if the whole dispatch fails, never per arm.

X-Shopify-Hmac-Sha256
Any of:
string
Media typeapplication/json
PdpExtractionRequest

POST /v1/pdp-extractions — one brand photograph into four owned entities (TRI-39).

The inverse of a composition dispatch. Instead of assembling a model, a background, a garment and a photography recipe into a picture, this reads a picture the brand already shipped back into those four parts — so a client with an existing catalogue onboards by uploading PDPs rather than authoring five forms by hand. All four land owned by the calling client; none of them reaches the shared Figur library.

Named for its INPUT. POST /v1/extract on this same surface already means pulling garments out of a trial photo and returns a different shape entirely, so “extraction” alone would have been ambiguous at the one place ambiguity is most expensive — the public API.

Ownership is absent by design and extra="forbid" keeps it that way: the client comes from the authenticated principal, and a caller-supplied owner is a rejected request rather than a silently ignored field.

Partial success is the normal case, not an error. A flat-lay PDP has no person, so the model arm produces nothing and the job still succeeds with the other three — read the terminal event’s failures for the reason per arm.

object
pdp_image_public_id
required
Pdp Image Public Id

The asset_id of the product photograph, from POST /v1/uploads.

string
>= 26 characters <= 26 characters
product_name
Any of:
string
>= 1 characters <= 200 characters
product_description
Any of:
string
>= 1 characters <= 1000 characters
Examples
Examplebasic

A brand's own product photograph

{
"pdp_image_public_id": "01JUPLOAD0000000000000000A",
"product_name": "Emerald Silk Saree"
}

Accepted — job queued. Poll /v1/jobs/{job_id} for the four entities.

Media typeapplication/json
WorkflowAcceptedResponse

Returned synchronously from any POST /v1/{name} (202).

object
request_id
required
Request Id

26-char ULID — correlates with the row in credit_operations.

string
job_id
required
Any of:
string
status
JobStatus

Studio’s job status at submit time. Almost always NOT_STARTED in this 202.

string
default: NOT_STARTED
Allowed values: NOT_STARTED SUCCESS FAILURE IN_PROGRESS
credits_cost
required
Credits Cost

Credits deducted from the calling client. Refunded automatically on any failure path.

integer
Example
{
"request_id": "01JREQREQREQREQREQREQREQ00",
"job_id": "01JOBJOBJOBJOBJOBJOBJOBJOB0",
"status": "NOT_STARTED",
"credits_cost": 10
}

Insufficient credit balance — the request cost exceeds the client’s balance. No job created.

Media typeapplication/json
Example
{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Account balance is below the cost of this request.",
"request_id": "01JREQREQREQREQREQREQREQ00"
}
}

Request body failed validation (missing/invalid fields). No credits charged.

Media typeapplication/json
Example
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request body or parameters failed validation.",
"request_id": "01JREQREQREQREQREQREQREQ00"
}
}

Per-credential rate limit exceeded. Retry after a short backoff.

Media typeapplication/json
Example
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded; try again shortly.",
"request_id": "01JREQREQREQREQREQREQREQ00"
}
}