Extract a background, model, product and shot recipe from one PDP photograph
const url = 'https://example.com/v1/pdp-extractions';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"pdp_image_public_id":"01JUPLOAD0000000000000000A","product_name":"Emerald Silk Saree"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}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.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”Request Bodyrequired
Section titled “Request Bodyrequired”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
Examples
A brand's own product photograph
{ "pdp_image_public_id": "01JUPLOAD0000000000000000A", "product_name": "Emerald Silk Saree"}Responses
Section titled “Responses”Accepted — job queued. Poll /v1/jobs/{job_id} for the four entities.
Returned synchronously from any POST /v1/{name} (202).
object
26-char ULID — correlates with the row in credit_operations.
Studio’s job status at submit time. Almost always NOT_STARTED in this 202.
Credits deducted from the calling client. Refunded automatically on any failure path.
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.
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.
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.
Example
{ "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded; try again shortly.", "request_id": "01JREQREQREQREQREQREQREQ00" }}