Neurall

Product Shot

imageimage/product-shot

One product photo becomes a full shoot: new scenes, surfaces and lighting, the product itself untouched.

The product photoThe product photoRestaged on wet slate, product untouchedRestaged on wet slate, product untouched

Its own feature, not a flag on a general edit. What makes it a product shot is the fidelity clause the server appends: the render is instructed to reproduce your product exactly, down to the labels and proportions, while everything around it is new.

Billed per image. $0.15 per look, or $0.53 with fineDetails on. Live rate from GET /v3/pricing.

A complete call

Restage a saved product photo on wet slate.

1Upload the product photo

POST /v3/files/upload returns a file id. A clean shot on any background works; the scene is replaced.

curl -X POST "https://api.neurall.io/v3/files/upload" \
  -H "Authorization: nl-YOUR_API_KEY" \
  -F "files=@candle.jpg"

It answers with the file ids

{
  "files": [
    {
      "id": "f_9c21e0b4",
      "originalName": "candle.jpg",
      "size": 468920
    }
  ]
}

2Submit the render

POST /v3/generations with feature image/product-shot and the file id from step 1.

curl -X POST "https://api.neurall.io/v3/generations" \
  -H "Authorization: nl-YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "feature": "image/product-shot",
    "args": {
      "image": "f_9c21e0b4",
      "description": "hand-poured soy candle in amber glass, sea salt and sage",
      "prompt": "Product on wet slate with rippling water, moody side light, dramatic reflections, deep shadow falloff.",
      "aspectRatio": "4:5",
      "fineDetails": true
    }
  }'

It answers immediately

{
  "generation": {
    "id": "c9b2…",
    "feature": "image/product-shot",
    "kind": "image",
    "status": "pending"
  }
}

3Poll until it lands

Poll GET /v3/generations/{id}, or pass webhookUrl and skip polling.

# repeat every 2s or so until status is done, error or timeout
curl "https://api.neurall.io/v3/generations/9f2c1d84-6a3b-4f21-9c77-2f0a1b8e5d43" \
  -H "Authorization: nl-YOUR_API_KEY"

Once status is done

{
  "generation": {
    "status": "done",
    "output": {
      "image": "https://cdn.neurall.io/…/image.png",
      "mime": "image/png"
    }
  }
}

output holds the finished asset on a signed CDN URL. Download it rather than hotlinking: API-created outputs expire 24 hours after the request.

Arguments

imagestringrequired
The file id of the product photo. Singular: this feature takes exactly one.
  • PNG, JPEG, WebP, GIF, HEIC or AVIF, up to 30 MB and 30 megapixels per file, 10 files per upload request.
  • An uploaded file is deleted 24 hours after it lands, so upload again for a later render rather than caching an id.
  • Exactly one image. A second reference is rejected: a product shot is about the product.

How the prompt refers to this

args.imageThe product
Say "the product" in the prompt when you need to place it ("the product on wet slate"). Do not describe what it looks like.
descriptionstring
What the product IS, in plain words. Ground truth the prompt author cannot guess from pixels, and the one thing worth saying about the product itself.

How the prompt refers to this

args.descriptionWhat the product is
Not a prompt: it is a fact the render can rely on, like "amber glass candle". Use it when the shape alone is ambiguous.
promptstringrequired
The scene: surface, backdrop, light, mood. Pure style, no fidelity language needed.
  • At most 2000 characters.
aspectRatio'W:H'defaults to '1:1'
Any ratio written as width:height.
  • Between 1:3 and 3:1.
fineDetailsbooleandefaults to false
The render tier, as one switch. Off is the standard render; on costs more and holds fine texture and small type. Sending quality here is an error: this feature owns the mapping so the tier that renders and the tier that bills cannot disagree.

Describing the product in the prompt competes with the photograph. Describe the scene; let the image be the product.

Output

Once status is done, the generation carries an output object with these fields. On any other status, output is absent.

imagestring
The finished shot, as a URL.
  • A signed URL that expires 24 hours after the request (expiresAt on the generation). Download the file rather than hotlinking it.
mimestring
The image's MIME type, e.g. image/png.

Limits and failure

Images
Exactly one, 30 MB and 30 megapixels max, deleted 24 hours after upload.
Aspect ratio
Any W:H between 1:3 and 3:1.
Render time
A generation that has not finished in 15 minutes is marked timeout and refunded.
Concurrency
Your plan caps how many generations run at once. Over it the API answers 429 with a Retry-After header.
Output lifetime
API-created outputs expire 24 hours after the request. Download the file rather than hotlinking it.
Deletion
DELETE /v3/generations/{id} removes the generation and its rendered assets immediately, rather than waiting for the 24 hour expiry. It does not refund anything and cannot cancel a render already in flight.
Failure
A failed or timed-out generation is refunded automatically.

Worth knowing

  • Its own feature key since 2026-08-13, so it prices, counts and lists on its own rather than hiding inside image/edit.
  • The upscaler is never run here. It is a face and skin model, so on a product it buys nothing but time, and the price quoted is the plain render.