# Bria Product Shot (image-edit) > Bria Product Shot drops a product cut-out into a scene that you describe, and holds the shape, the label and the proportions of the product while the background changes around it. It is the roasOS product-placement step, and it is the model behind the `product` lane of a statics run. Status: roasOS API v1.1. Catalog `model-catalog@2026-10-06.v5`, pricing `customer-pricing@2026-11-05.v15`. The endpoint `POST /v1/image-edit/bria-product-shot` is live. `POST /v1/generations` has no `image-edit` type, so this endpoint is the only path to this model. ## Endpoint POST https://api.roasos.com/v1/image-edit/bria-product-shot Auth: Authorization: Bearer roasos_sk_… (scope api:write). Idempotency-Key required. quote_only / quote_id / webhook_url as in https://docs.roasos.com/llms.txt. ## Good at A packshot that must become a lifestyle image without the product drifting. Bria states that the model is "trained exclusively on licensed data for safe and risk-free commercial use and optimized for eCommerce" (https://fal.ai/models/fal-ai/bria/product-shot, read 2026-08-21). It is the one model on this roster with a stated licensed-training-data claim, and that claim, plus the product integrity, is why roasOS adopted it for placement instead of a general image editor. Feed it the cut-out that your product kit already built on /v1/image-edit/bria-bg-remove: the model expects a transparent-background PNG, and a photo with a busy background gives a worse placement. Use /v1/image/nano-banana-pro instead when the whole frame is generated, when the frame needs a person, or when the frame needs rendered type — this model writes no text. ## Pricing Unit: operation. Pricing key: `bria-product-shot`. | request | credits | |---|---| | `1_image` | 1 | Credits come from the roasOS pricing table (`MODEL_COSTS`) through the catalog. No other field changes the price. ## Modes - `product-shot` Provider endpoints: `fal-ai/bria/product-shot`. ## Request fields | field | type | required | default | rule | |---|---|---|---|---| | `image_url` | string | yes | — | https URL; ≤ 4,096 characters | | `prompt` | string | yes | — | ≥ 1 character; ≤ 1,000 characters | | `quote_id` | string | no | — | UUID | | `quote_only` | boolean | no | `false` | — | | `wait_timeout_seconds` | integer | no | `0` | 0–60 | | `webhook_url` | string | no | — | https URL; ≤ 4,096 characters | The schema is strict: a field that is not in this table returns `400 unsupported_option`. Field names are the roasOS role names, one name per role across every family. ## Media - `image_url` — first frame (or the single source image) | role | items | max size | content types | duration | |---|---|---|---|---| | `image_url` | ≤ 1 | 10 MB | `image/jpeg`, `image/png`, `image/webp` | — | - Refused: `avatar_id`, `elements`, `product_id`, `product_images`, `references`, `reference_images`, `end_image_url`, `scene_id`, `scene_image`, `video_urls`, `video_url`, `audio_urls`, `audio_url`, `voice_id`. A refused role returns `400 unsupported_option`. - Every URL must be an immutable object on `https://cdn.roasos.com/…` that your workspace owns; any other URL is `400 reference_media_not_workspace_owned`. Upload with `POST /v1/uploads` (direct POST of the bytes to `put_url`, or a `source_url` import), then use the returned CDN URL. ## Prompt Describe the scene, not the product. The model already holds the product as pixels, so spend the words on the surface it stands on, the light and the setting: "on a rock, next to the ocean, dark theme" is the shape of Bria's own example. Write in English. Avoid special characters. Do not ask for a headline, a logo or a label — the placement keeps the product's own label, and a second rendered one fights it. Keep the description under 1,000 characters. The output is one image at about 1 MP, in the placement that roasOS pins; there is no aspect-ratio field, because the output shape is pinned too. ## Not exposed - `num_results`: pinned to `1`. - `placement_type`: pinned to `manual_placement`. - `manual_placement_selection`: pinned to `bottom_center`. - `shot_size`: values not exposed — `1000`, `1000`. - `padding_values`: not accepted by this public endpoint. - `original_quality`: not accepted by this public endpoint. - `ref_image_url`: not accepted by this public endpoint. - `optimize_description`: pinned to `true`. - `fast`: pinned to `true`. - `sync_mode`: not accepted by this public endpoint. ## Result Result kind `image`. Always present: nothing. Present when the run produces it: `avatar_id`, `full_body_url`, `images`, `portrait_url`, `provider_seed`, `reference_sheet`, `url`. ```json { "data": { "id": "gen_…", "kind": "image", "model": "bria-product-shot", "status": "completed", "result": {"avatar_id":"00000000-0000-4000-8000-000000000000","full_body_url":"https://cdn.roasos.com/workspaces/ws_01/full_body_url","images":["https://cdn.roasos.com/workspaces/ws_01/images-1.png"],"portrait_url":"https://cdn.roasos.com/workspaces/ws_01/portrait_url","provider_seed":0,"reference_sheet":"https://cdn.roasos.com/workspaces/ws_01/reference_sheet","url":"https://cdn.roasos.com/workspaces/ws_01/result"} } } ``` Files live on `https://cdn.roasos.com` and are immutable; a result URL can be a media input to the next call. Poll `GET /v1/jobs/{id}/status` → `{ id, status, updated_at }`, then `GET /v1/jobs/{id}/result` (`409 run_not_completed` until the job is `completed`, `failed` or `canceled`). Statuses: `queued → processing → completed | failed | canceled`. ## Example ```bash # 1. quote — nothing is spent curl -X POST https://api.roasos.com/v1/image-edit/bria-product-shot \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-bria-product-shot-0001" \ -H "Content-Type: application/json" \ -d '{"quote_only":true,"image_url":"https://cdn.roasos.com/workspaces/ws_01/uploads/image_url.png","prompt":"A woman holds the bottle at eye level in a bright kitchen, morning light, static camera."}' # → 200 { "data": { "kind": "quote", "quote_id": "q_7Hk…", "credits": 1, "expires_at": "…", "confirmation": { "model": "bria-product-shot", "example": "1_image" } } } # 2. run — the same body and the same Idempotency-Key, quote_id instead of quote_only curl -X POST https://api.roasos.com/v1/image-edit/bria-product-shot \ -H "Authorization: Bearer roasos_sk_live_…" \ -H "Idempotency-Key: 0f1c9e2a-bria-product-shot-0001" \ -H "Content-Type: application/json" \ -d '{"quote_id":"q_7Hk…","image_url":"https://cdn.roasos.com/workspaces/ws_01/uploads/image_url.png","prompt":"A woman holds the bottle at eye level in a bright kitchen, morning light, static camera."}' # → 201 { "data": { "id": "gen_…", "kind": "image", "model": "bria-product-shot", "status": "queued", "credits_reserved": 1, "links": { "status": "/v1/jobs/gen_…/status", "result": "/v1/jobs/gen_…/result" } } } # 3. poll curl https://api.roasos.com/v1/jobs/gen_…/status -H "Authorization: Bearer roasos_sk_live_…" curl https://api.roasos.com/v1/jobs/gen_…/result -H "Authorization: Bearer roasos_sk_live_…" ``` ## Today `POST /v1/image-edit/bria-product-shot` costs **1 credit** for one generation, flat. No field of the request changes that price. The reason the price has one shape is that roasOS pins the provider controls that would move it: `num_results` is pinned to 1, and `placement_type` is pinned to `manual_placement` with a `bottom_center` placement. At the provider's own `automatic` placement one request returns ten images per result, so an exposed count would be an unbounded bill against one flat published price. The request therefore takes two fields only: the cut-out in `image_url`, and the scene in `prompt`. `POST /v1/generations` has no `image-edit` type, so this endpoint is the only public path to this model. The endpoint is an API capability first: the roasOS agent does not offer it as a tool yet, so the `product` lane of a statics run falls back to Nano Banana Pro with the cut-out as a reference until it does. ## See also https://docs.roasos.com/models/image-edit/bria-product-shot · https://api.roasos.com/v1/catalog/image-edit/bria-product-shot · fal-ai/bria/product-shot