> ## Documentation Index
> Fetch the complete documentation index at: https://docs.makelocalads.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Quick Shoot

> Turn a product URL or a product image into a fixed number of finished photos.

Quick Shoot takes a product, a look, and a count, and returns that many finished
images. It is the API behind the Quick Shoot controls in the LocalAds workspace.

Everything runs asynchronously. Each requested image consumes one credit.

## What you supply

| Input                    | Where it goes                    | Notes                                                                   |
| ------------------------ | -------------------------------- | ----------------------------------------------------------------------- |
| A product page URL       | `source_url` on `POST /products` | LocalAds reads the page for the product's name, description, and images |
| One or more image URLs   | `image_urls` on `POST /products` | Public HTTPS URLs, or URLs returned by `POST /uploads/images`. Up to 6  |
| The look                 | `quick_shoot.look`               | `standard`, `close_up`, `lifestyle`, `out_of_the_box`, or `retro`       |
| How many images you want | `quick_shoot.count`              | `1`, `3`, `5`, `8`, or `15`                                             |

`source_url` and `image_urls` are alternatives. Send one or the other, not both.

You need an API key with `products:create` and `photoshoots:generate`, and
enough credits for every requested image.

## 1. Create the product

From a product page URL:

```bash theme={null}
curl --request POST \
  --url https://makelocalads.com/api/v1/products \
  --header "Authorization: Bearer $LOCALADS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "brand_id": "1423f915-beca-4c53-a5e4-7c8c99537be9",
    "source_url": "https://shop.example.com/products/hydrating-face-serum"
  }'
```

Or from images you already have:

```bash theme={null}
curl --request POST \
  --url https://makelocalads.com/api/v1/products \
  --header "Authorization: Bearer $LOCALADS_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "brand_id": "1423f915-beca-4c53-a5e4-7c8c99537be9",
    "name": "Hydrating Face Serum",
    "image_urls": ["https://cdn.example.com/serum-front.jpg"]
  }'
```

Both return `202 Accepted` with `status: "processing"`. LocalAds is fetching the
page or the images. Retrieve the product until its status is `ready`:

```bash theme={null}
curl https://makelocalads.com/api/v1/products/a1516a75-9be5-461a-93af-c1896a0a3127 \
  --header "Authorization: Bearer $LOCALADS_API_KEY"
```

A Quick Shoot needs the product to have at least one image, so wait for `ready`
before the next step. A product only needs creating once. Reuse its `id` for
every later shoot.

If your image is only on disk, upload it first with
[`POST /uploads/images`](/guides/create-photoshoot) and use the returned `url`.

## 2. Start the Quick Shoot

```bash theme={null}
curl --request POST \
  --url https://makelocalads.com/api/v1/photoshoots \
  --header "Authorization: Bearer $LOCALADS_API_KEY" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: quick-shoot-1042" \
  --data '{
    "product_id": "a1516a75-9be5-461a-93af-c1896a0a3127",
    "quick_shoot": {
      "look": "retro",
      "count": 5
    }
  }'
```

```javascript theme={null}
const response = await fetch("https://makelocalads.com/api/v1/photoshoots", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.LOCALADS_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "quick-shoot-1042",
  },
  body: JSON.stringify({
    product_id: "a1516a75-9be5-461a-93af-c1896a0a3127",
    quick_shoot: { look: "retro", count: 5 },
  }),
});

const photoshoot = await response.json();
```

The response is `202 Accepted` with one `outputs` entry per requested image, all
`queued`, and a `Location` header pointing at the photoshoot.

Reusing an `Idempotency-Key` after a network failure returns the original
photoshoot instead of starting and charging for a second one.

### Looks

| `look`           | Workspace label | Output size                |
| ---------------- | --------------- | -------------------------- |
| `standard`       | Standard        | Square, 1024x1024          |
| `close_up`       | Close-up        | Square, 1024x1024          |
| `lifestyle`      | Lifestyle       | Square, 1024x1024          |
| `out_of_the_box` | Out of the box  | Square, 1024x1024          |
| `retro`          | Retro           | Card, 1200x1800 at 300 DPI |

`look` defaults to `standard` and `count` defaults to `1`.

### Optional direction

Add `direction` to steer the shoot with text, reference images, or both:

```json theme={null}
{
  "product_id": "a1516a75-9be5-461a-93af-c1896a0a3127",
  "quick_shoot": {
    "direction": {
      "text": "Place the product on a stone pedestal in warm sunlight.",
      "image_urls": ["https://cdn.example.com/reference.jpg"]
    },
    "look": "lifestyle",
    "count": 3
  }
}
```

When `direction` is present it must carry text or at least one image URL. Up to
eight HTTPS images. Third-party URLs must load without cookies or authorization
headers.

## The retro look

`retro` is a generative look. The other looks apply a fixed treatment to the
product. `retro` reads the product first, then invents a different printed scene
for every image in the shoot, in the register of mid-century Indian print
culture: souvenir and advertising cards, halftone screens, faded ink, paper
grain.

Three things behave differently:

* **Output is a print-ready 4 x 6 card.** Every image is 1200x1800 at 300 DPI:
  the artwork mounted on aged paper, the card's line set in italics beneath it,
  and the localads mark in the corner. It prints as it arrives, no layout step
  on your side.
* **`direction.image_urls` are ignored.** Each scene is composed from the
  product itself. `direction.text` is still read and used as guidance.
* **The first image takes about a minute longer.** The look derives a brief from
  the product and renders one shared reference packshot before any output
  starts. Every image in the shoot uses that same packshot, which is what keeps
  the set reading as one product. Later images arrive at the usual pace.

Ask for more than one image when you use it. Each card is a distinct printed
format, so a shoot of `5` or `8` shows the range. A shoot of `1` returns one
card and none of the variety the look exists for.

## 3. Poll for the images

```bash theme={null}
curl https://makelocalads.com/api/v1/photoshoots/e8766ffd-66f7-47c9-86bc-0d93e6868d06 \
  --header "Authorization: Bearer $LOCALADS_API_KEY"
```

Finished images appear on their outputs while the rest continue:

```json theme={null}
{
  "id": "e8766ffd-66f7-47c9-86bc-0d93e6868d06",
  "brand_id": "1423f915-beca-4c53-a5e4-7c8c99537be9",
  "product_id": "a1516a75-9be5-461a-93af-c1896a0a3127",
  "template_id": null,
  "status": "in_progress",
  "outputs": [
    {
      "id": "19025a65-5395-41c9-af90-d7cca7fb6421",
      "position": 1,
      "status": "completed",
      "image_url": "https://cdn.example.com/generated-card-1.png",
      "width": 1200,
      "height": 1800,
      "caption": "The mill ran two shifts and the tea went out by the crate. Somebody's mother packed the first one. You can still taste that care in the cup."
    },
    {
      "id": "4f52bad2-2da3-4b36-93ac-03788f35daca",
      "position": 2,
      "status": "in_progress",
      "image_url": null,
      "width": null,
      "height": null,
      "caption": null
    }
  ],
  "created_at": "2026-07-24T15:00:00.000Z",
  "updated_at": "2026-07-24T15:00:04.000Z"
}
```

Stop polling when `status` is `completed`, `failed`, or `canceled`. Use backoff
between requests rather than polling continuously. Individual outputs can fail
while the rest of the shoot succeeds, so check each output's own `status`.

`caption` is the line printed in italics under the artwork. It is part of the
card, so take it with the image. The `retro` look writes a different one for
every output, tied to what that specific card shows. Every other look returns
`null`.

Every completed image for a product stays retrievable without tracking
individual photoshoot IDs:

```bash theme={null}
curl "https://makelocalads.com/api/v1/products/a1516a75-9be5-461a-93af-c1896a0a3127/creatives?type=photoshoot" \
  --header "Authorization: Bearer $LOCALADS_API_KEY"
```

## Errors worth handling

| Status | Code                     | What happened                                                 |
| ------ | ------------------------ | ------------------------------------------------------------- |
| 400    | `invalid_request`        | An unknown field, or a `count` outside the allowed values     |
| 404    | `product_not_found`      | The product does not exist or belongs to another organization |
| 422    | `missing_product_images` | The product has no images yet. Wait for `status: "ready"`     |
| 422    | `insufficient_credits`   | Fewer credits than requested images                           |
| 409    | `idempotency_conflict`   | The `Idempotency-Key` was reused with a different body        |

Full error format is in [Errors](/errors).
