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 × Σ poses images, 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}}]

  • array<string>required

    Who wears the products, as ["model:<id>", …], at least one — a base model or one of its STYLES (GET /v1/refs/model lists 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 keep to leave each photo's own scene, or pick or describe one.

    Example: {"type":"library","background":"background:77"}

  • array<object>optional

    Product views to make of EVERY product besides the images on models, one {type, view} each — ghost (on an invisible mannequin) or flat (laid flat) with its side, front, back or side, or {"type": "close_up"} for one close-up of each product. A product's own views replace these for it. reuse: true copies 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"}]

  • stringoptionalDefault: 9:16

    The shape of every image. 9:16 is 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: 2K

    The size of every image. 2K is sharp enough for screens and review; ask for 4K when 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). Its data.items are the shoot's images — type: look on a model, ghost or flat with its view (front · back · side) for a product view, close_up — each with its url and named by its product: the product's own name, else Product <n> by its place in products, and its external_id (SKU) when it has one. An image that failed carries status: failed and no url. Read it again with GET /v1/files/photoshoot:<id>; pass any items[].url into 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.

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 in data.items.
  • Each image's url, its type (look on a model, or a product view and its side) and the product it shows, by name and SKU.
  • A summary that counts the images asked for and made, and warns about any image not made.

Specs

Input formatsImages, 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 countproducts: at least 1, each with its image
Output formatOne photoshoot: record: its data is JSON in the record vocabulary, its url a preview image.
Output resolution2K, 4K
Aspect ratios1:1, 3:4, 4:3, 9:16, 16:9, 2:3, 3:2, 4:5
Outputs per jobOne 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

Errors

Good to know

  • name is at most 255 characters.
  • products holds at least 1 items.
  • products[].items holds at most 4 items.
  • models holds at least 1 items.

Pricing: Estimate a request before you run it, or see the price of each option.

For agents and code generation

Schema changes follow Versioning.