For AI agents: this page is also available as Markdown at https://docs.refabric.com/task-api-reference/photoshoot.create.md, and the index of every page is https://docs.refabric.com/llms.txt.
Photoshoots
Create a photoshoot
Shoot your garments on AI models: each product on each model in its poses, on one backdrop, with optional product views. Delivered as one record whose items are the images.
Endpoint: POST https://api.refabric.com/v1/tasks/photoshoot.createTask: photoshoot.createScope: tasks:runCategory: Photoshoots
Quick start
import os
import time
import requests
headers = {"Authorization": f"Key {os.environ['REFABRIC_API_KEY']}"}
job = requests.post(
"https://api.refabric.com/v1/tasks/photoshoot.create",
headers=headers,
json={
"products": [
{
"image": "file:812",
},
],
"models": [
"model:5501",
],
},
).json()
print(job["job_id"])
while True:
status = requests.get(job["status_url"], headers=headers).json()
if status["lifecycle"] == "terminal":
break
time.sleep(5)
print(requests.get(job["result_url"], headers=headers).json())cURL waits for the result with Prefer: wait; when the job outlives the wait, it answers 202 with the job's URLs.
Input schema
- array<object>required
The garments to shoot, one entry each, at least one. Every product is shot on every model in each of its poses:
models × Σ posesimages, at most 100.at least 1 items
Example:
[{"image":"file:812","items":[{"image":"https://files.example.com/photoshoot.create/1.jpg"}],"styling":"sleeves pushed up, shirt tucked in","poses":{"type":"custom","items":[{"type":"library","pose":"pose:3f7c1a52-0000-4000-8000-000000000001"},{"type":"prompt","prompt":"walking toward the camera"}]},"views":[{"type":"ghost","view":"front","reuse":true},{"type":"ghost","view":"back"},{"type":"close_up"}]},{"image":"art:c10d55","poses":{"type":"auto","count":2}}]- stringrequired
The garment's photo, as one string (a url,
art:…orfile:…) — flat or worn; either works. A url or file of one of your products is that product: its back and detail photos, its category (POST /v1/files) and its saved views come with it.pattern: ^(https://|art:|file:).+$
Example:
file:812 - array<object>optional
Up to 4 other garments worn with it in every image — shoes, a bag, a jacket (the outfit). What each one is comes from its own product: the category it was uploaded with (
POST /v1/files).at most 4 items
Example:
[{"image":"https://files.example.com/photoshoot.create/1.jpg"}]- stringrequired
The garment's photo.
pattern: ^(https://|art:|file:).+$
Example:
https://files.example.com/photoshoot.create/1.jpg
- stringoptional
How the product is worn, in one sentence — 'sleeves pushed up, shirt tucked in, jacket open'. It steers the pose and the render.
Example:
sleeves pushed up, shirt tucked in - objectoptional
This product's poses: an object whose
typesays how they are chosen.Example:
{"type":"custom","items":[{"type":"library","pose":"pose:3f7c1a52-0000-4000-8000-000000000001"},{"type":"prompt","prompt":"walking toward the camera"}]}type: auto
The poses are chosen for you, as many as
count— the samecountfor every product of the shoot whose poses are chosen.- stringrequired
Picks this alternative:
auto.Values
auto
- integerrequired
How many, 1–20.
1 to 20
type: custom
You list each pose — from the library, a picture, or in words — in order.
- stringrequired
Picks this alternative:
custom.Values
custom
- array<object>required
What you list: 1–40 entries, each used once, in order.
at least 1 items · at most 40 items
type: library
One pose from the library, as
pose:<id>(listed atGET /v1/refs/pose).- stringrequired
Picks this alternative:
library.Values
library
- stringrequired
A
pose:<id>handle, listed atGET /v1/refs/pose.pattern: ^pose:.+$
type: image
A picture of the pose you want (a url,
art:…orfile:…).- stringrequired
Picks this alternative:
image.Values
image
- stringrequired
A picture, as one string: a URL, a file from an earlier result (
art:…, or itsurl) or an upload (file:…).pattern: ^(https://|art:|file:).+$
type: prompt
Describe it in words.
- stringrequired
Picks this alternative:
prompt.Values
prompt
- stringrequired
What you want, in words.
min length 1
- array<object>optional
This product's own views — they REPLACE the shoot's
viewsfor it.reuse: truecopies the view the product already has saved instead of making it (not charged); a view it has not saved is made as usual, and the result says so (summary.warnings[]view_generated).Example:
[{"type":"ghost","view":"front","reuse":true},{"type":"ghost","view":"back"},{"type":"close_up"}]- stringrequired
What the view is.
Values
ghost— The product on an invisible (ghost) mannequin (view: which side). When you want the product shown on an invisible mannequin.flat— The product laid flat, as a flat-lay photo (view: which side). When you want the product laid flat.close_up— A close-up of the product's fabric and finish (one per product in a shoot). Notdetail, which is a crop of one trim or component of a look. When you want a close-up of the product's fabric and finish.
Example:
ghost - stringoptional
Which side it shows. Not sent for a
close_up.Values
front— The front of the product. For the main product image.back— The back of the product. To show what is on the back: closures, pockets, prints.side— The side of the product. To show the product's profile and fit.
Example:
front - booleanoptional
Copy the view this product already has saved instead of making it again. Omitted, false.
Example:
true
- array<string>required
Who wears the products, as ["model:<id>", …], at least one — a base model or one of its STYLES (
GET /v1/refs/modellists both;?base=model:<id>lists one model's styles). A style changes hair, make-up and face, not the outfit, and counts as one more model: every product is shown on every model you name, so each one multiplies the images.at least 1 items
Example:
["model:5501"] - stringoptional
The shoot's name, as it appears in your library and as the record's
data.name(at most 255 characters). Omitted: the kind of shoot and the day it was started, in UTC — "Photoshoot 2026-10-01".max length 255
Example:
SS27 lookbook - objectoptionalDefault:
{"type":"auto"}The one backdrop of the shoot, behind every image. The backdrop is chosen for you, so a shoot needs no scene from you. Send
keepto leave each photo's own scene, or pick or describe one.Example:
{"type":"library","background":"background:77"}type: auto
The backdrop is chosen for you.
- stringrequired
Picks this alternative:
auto.Values
auto
type: keep
Every photo keeps its own scene (a worn photo's backdrop).
- stringrequired
Picks this alternative:
keep.Values
keep
type: library
One backdrop of the library, behind every image.
- stringrequired
Picks this alternative:
library.Values
library
- stringrequired
A
background:<id>handle, listed atGET /v1/refs/background.pattern: ^background:.+$
type: prompt
The scene in your words, behind every image.
- stringrequired
Picks this alternative:
prompt.Values
prompt
- stringrequired
What you want, in words.
min length 1
- array<object>optional
Product views to make of EVERY product besides the images on models, one
{type, view}each —ghost(on an invisible mannequin) orflat(laid flat) with its side,front,backorside, or{"type": "close_up"}for one close-up of each product. A product's ownviewsreplace these for it.reuse: truecopies the view a product already has saved (not charged); one it has not saved is made, and the result says so (view_generated). Each made view counts as an image. Omitted, none.Example:
[{"type":"ghost","view":"front"},{"type":"ghost","view":"back"},{"type":"close_up"}]- stringrequired
What the view is.
Values
ghost— The product on an invisible (ghost) mannequin (view: which side). When you want the product shown on an invisible mannequin.flat— The product laid flat, as a flat-lay photo (view: which side). When you want the product laid flat.close_up— A close-up of the product's fabric and finish (one per product in a shoot). Notdetail, which is a crop of one trim or component of a look. When you want a close-up of the product's fabric and finish.
Example:
ghost - stringoptional
Which side it shows. Not sent for a
close_up.Values
front— The front of the product. For the main product image.back— The back of the product. To show what is on the back: closures, pockets, prints.side— The side of the product. To show the product's profile and fit.
Example:
front - booleanoptional
Copy the view this product already has saved instead of making it again. Omitted, false.
- stringoptionalDefault:
9:16The shape of every image.
9:16is a tall portrait frame, the shape that fits a model standing in the picture. Send another ratio when your page or feed uses a different shape.Values
1:1— Square. For square places: product grids and social posts.3:4— Portrait, slightly taller than wide. For portrait product pages.4:3— Landscape, slightly wider than tall. For landscape layouts and slides.9:16— Tall portrait, as for phone screens and stories. For phone screens: stories and reels.16:9— Wide landscape, as for banners and video. For banners, headers and video frames.2:3— Portrait, as for a classic photo print. For a portrait print or a lookbook page.3:2— Landscape, as for a classic photo print. For a landscape print.4:5— Portrait, as for social feeds. For portrait posts in social feeds.
Example:
3:4 - stringoptionalDefault:
2KThe size of every image.
2Kis sharp enough for screens and review; ask for4Kwhen the result will be printed or zoomed into.Values
2K— Standard size, for screens and review.4K— Large size, for print and zoom. When the image will be printed or zoomed into.
Example:
2K
Output schema
- array<object>optional
ONE file: the shoot,
photoshoot:<id>(application/json). Itsdata.itemsare the shoot's images —type: lookon a model,ghostorflatwith itsview(front · back · side) for a product view,close_up— each with itsurland named by its product: the product's own name, elseProduct <n>by its place inproducts, and itsexternal_id(SKU) when it has one. An image that failed carriesstatus: failedand no url. Read it again withGET /v1/files/photoshoot:<id>; pass anyitems[].urlinto an edit (image.polish, …). - objectoptional
How many images the shoot holds, how many came out with an image, and a warning for any that did not.
- integeroptional
The shoot's images.
- integeroptional
How many of them have an image.
- array<object>optional
{code, field, message}rows: one when some images were not produced (code: "output_not_produced",field: "items"; they are in the record without a url), and one per view asked to be reused that the product had not saved, so it was made (code: "view_generated").
Required-fields example
{
"products": [
{
"image": "file:812"
}
],
"models": [
"model:5501"
]
}Full example
{
"name": "SS27 lookbook",
"products": [
{
"image": "file:812",
"items": [
{
"image": "https://files.example.com/photoshoot.create/1.jpg"
}
],
"styling": "sleeves pushed up, shirt tucked in",
"poses": {
"type": "custom",
"items": [
{
"type": "library",
"pose": "pose:3f7c1a52-0000-4000-8000-000000000001"
},
{
"type": "prompt",
"prompt": "walking toward the camera"
}
]
},
"views": [
{
"type": "ghost",
"view": "front",
"reuse": true
},
{
"type": "ghost",
"view": "back"
},
{
"type": "close_up"
}
]
},
{
"image": "art:c10d55",
"poses": {
"type": "auto",
"count": 2
}
}
],
"models": [
"model:5501"
],
"background": {
"type": "library",
"background": "background:77"
},
"views": [
{
"type": "ghost",
"view": "front"
},
{
"type": "ghost",
"view": "back"
},
{
"type": "close_up"
}
],
"aspect_ratio": "3:4",
"resolution": "2K"
}Response example
{
"job_id": "0123456789abcdef0123456789abcdef",
"lifecycle": "queued",
"status_url": "http://v3-api.refabric.com/v1/jobs/0123456789abcdef0123456789abcdef",
"result_url": "http://v3-api.refabric.com/v1/jobs/0123456789abcdef0123456789abcdef/result",
"cancel_url": "http://v3-api.refabric.com/v1/jobs/0123456789abcdef0123456789abcdef/cancel"
}Result example
{
"job_id": "0123456789abcdef0123456789abcdef",
"files": [
{
"file": "photoshoot:0123456789abcdef0123456789abcdef",
"url": "https://files.example.com/photoshoot.create/2.png",
"media_type": "application/json",
"task": "photoshoot.create",
"job_id": "0123456789abcdef0123456789abcdef",
"created_at": "2026-10-01T10:14:02Z",
"data": {
"name": "SS27 lookbook",
"status": "ready",
"items": [
{
"type": "look",
"name": "Linen shirt",
"external_id": "SKU-812",
"url": "https://files.example.com/photoshoot.create/2.png"
},
{
"type": "look",
"name": "Linen shirt",
"external_id": "SKU-812",
"url": "https://files.example.com/photoshoot.create/3.png"
},
{
"type": "ghost",
"view": "front",
"name": "Linen shirt",
"external_id": "SKU-812",
"url": "https://files.example.com/photoshoot.create/4.png"
},
{
"type": "ghost",
"view": "back",
"name": "Linen shirt",
"external_id": "SKU-812",
"status": "failed"
},
{
"type": "close_up",
"name": "Linen shirt",
"external_id": "SKU-812",
"url": "https://files.example.com/photoshoot.create/5.png"
},
{
"type": "look",
"name": "Product 2",
"url": "https://files.example.com/photoshoot.create/6.png"
},
{
"type": "look",
"name": "Product 2",
"url": "https://files.example.com/photoshoot.create/7.png"
},
{
"type": "ghost",
"view": "front",
"name": "Product 2",
"url": "https://files.example.com/photoshoot.create/8.png"
},
{
"type": "ghost",
"view": "back",
"name": "Product 2",
"url": "https://files.example.com/photoshoot.create/9.png"
},
{
"type": "close_up",
"name": "Product 2",
"url": "https://files.example.com/photoshoot.create/10.png"
}
]
}
}
],
"has_more": false,
"summary": {
"requested": 10,
"delivered": 9,
"warnings": [
{
"code": "output_not_produced",
"field": "items",
"message": "1 of the shoot's 10 images were not produced; they are in the record without a url."
}
]
}
}One model × (2 listed poses + 2 poses chosen for you) = 4 looks, plus each product's ghost front / back and close-up. model:5501 is a style of a base model (GET /v1/refs/model?base=model:4412), passed as a model; each more model multiplies the looks. A product's own views replace the shoot's views for it; reuse: true uses the view the product already has saved — had it none, the view would be made and the result would carry a view_generated warning naming products[0].views[0]. Items are named per product: the library product's own name and its SKU (external_id); the art: image has no product name, so it is Product 2, its place in products.
Send photos of your garments and the models to wear them, and get a finished shoot back: every product on every model, in poses chosen for you or listed by you, on one backdrop for the whole shoot. Add product views of the same garments — on an invisible mannequin, laid flat or in close-up — in the same job.
Built for
- Store and catalogue images on models
- A lookbook with one cast and one backdrop
- On-model images and product views in one job
What you get
- One
photoshoot:record — the shoot's name, its status and its images indata.items. - Each image's
url, its type (lookon a model, or a product view and its side) and the product it shows, by name and SKU. - A
summarythat counts the images asked for and made, and warns about any image not made.
Specs
| Input formats | Images, each one string: a URL, an upload (file:…) or a file from an earlier result (art:…). Upload types and sizes: GET /v1/meta limits.upload. |
|---|---|
| Input count | products: at least 1, each with its image |
| Output format | One photoshoot: record: its data is JSON in the record vocabulary, its url a preview image. |
| Output resolution | 2K, 4K |
| Aspect ratios | 1:1, 3:4, 4:3, 9:16, 16:9, 2:3, 3:2, 4:5 |
| Outputs per job | One record file, however large the shoot. Its data.items hold, per product, one image for each pose on each model, plus the views you ask for. |
Choosing a task
- Use this when you have product photos and want them on models in new poses, on a backdrop you choose. Use mannequin_photoshoot.create when your photos already show the garment worn, on a mannequin or a person, and each photo's pose and framing should stay.
- Use this when you want the garments worn by models. Use ghost_photoshoot.create when you want the products alone, with nobody in the images.
Errors
field_not_acceptedfield_not_supportedinvalid_optioninvalid_requesttoo_many_outputsnot_foundrequest_refusedinsufficient_creditspermission_deniedcontent_refusedprocessing_failedtoo_many_references
Related
pose.create· It runs before: its result is this input.background.create· It runs before: its result is this input.image.polish· It runs after: it takes this task's result.
Good to know
nameis at most 255 characters.productsholds at least 1 items.products[].itemsholds at most 4 items.modelsholds at least 1 items.
Pricing: Estimate a request before you run it, or see the price of each option.
For agents and code generation
- https://api.refabric.com/v1/tasks/photoshoot.create/llms.txt
- https://api.refabric.com/v1/tasks/photoshoot.create/openapi.json
GET https://api.refabric.com/v1/tasks/photoshoot.create