Render a look

post/v2/agent/looks

Renders one outfit as a single styled image of a model wearing every item, from the product photos alone. Call it once for each look announced on a looks stream event (or in the non-streaming response's looks), passing that look's item ids, label and customInstructions. Fire the calls in parallel — each takes several seconds and they are independent, so a three-look answer finishes about as fast as a one-look answer.

The endpoint is not limited to agent output: any two to six active items from your catalogue can be rendered together. itemIds must be full item ids (the itemId on a Product), not the 13-character references the agent uses in its tool calls.

Items are resolved within your organization's datasets only. Every id must resolve to an active item in scope, or the request fails with 404 naming the ids that did not — a look is never rendered with pieces missing. When rendering a look from the agent, send the same datasetIds you sent to the chat endpoint; the agent picked its items from that scope, and the default (your active datasets) may not contain them.

The image is generated at a 3:4 aspect ratio by default so nothing is cropped when displayed in a portrait box; override it with preferences.aspectRatio. It is returned inline as a data: URI — there is no hosted URL, so store it yourself if you need to show it again.

Each request consumes one unit of api.v2.agent.looks, a resource of its own, separate from the v1 outfit endpoint. A 502 (or any other 5xx) is refunded.

Public keyapi.v2.agent.looksDemo key OK

Request body

application/jsonrequired
itemIdsarray<string>required

Full item ids of the garments worn together. Ids that do not resolve to an active item in scope are left out; at least two must resolve.

minItems: 2maxItems: 6
labelstring

Name of the look, used in the render prompt. Defaults to Look.

default: "Look"e.g. "Garden wedding"
datasetIdsarray<string>

Datasets to resolve the items in. Omit or send [] for every active dataset.

default: []
userPhotoUrlstring

The shopper's own photo, to style the look onto them instead of a stock model. A base64 data: URL of a JPEG, PNG or WebP image, at most 3 MB decoded — never a web URL. Stylor uses it for this request only and stores neither the photo nor the render made from it, so keep both in the shopper's browser if you need them again.

e.g. "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
object

Render preferences. Only aspectRatio is read today; other keys are accepted and ignored.

aspectRatiostring

Output aspect ratio as width:height, for example 3:4, 1:1, 9:16. Match it to the box you display the image in.

default: "3:4"e.g. "3:4"
customInstructionsstringnullable

Free-text direction for anything the product photos cannot convey. Pass the value from the look unchanged; omit or null when there is none.

e.g. "Shirt untucked with the top button open; outdoor daylight setting."
sessionIdstringnullable

Your identifier for the shopper's visit, for analytics only.

default: nulle.g. "3b0d4a1e-6f52-4b8a-9d3c-7e2f1a0b9c8d"
Session | null

Visit metadata for analytics.

default: null

Option 1: Session

surfacestring

Where the shopper is talking to the agent. Defaults to widget when omitted.

e.g. "widget"
agentVersionstring

Which agent version your client is built against. Use v2.

e.g. "v2"
storageModestring

How your client persists the visit id — for example memory, session or local. Defaults to memory.

e.g. "local"
tzstringnullable

The shopper's IANA time zone.

e.g. "America/Toronto"
localestringnullable

The shopper's BCP 47 locale.

e.g. "en-CA"
devicestringnullable

A coarse device class, typically mobile or desktop.

e.g. "desktop"

Option 2: null

Response

200The rendered look.

Response headers

X-RateLimit-Resource

The quota resource this endpoint is metered against: api.v2.agent.chat for the chat endpoint, api.v2.agent.looks for the looks endpoint and api.v2.agent.match for the shop-the-look endpoint. These are separate from the v1 resources, so Agent API usage never draws down a v1 allowance.

X-RateLimit-Quota-Limit

Requests allowed in the current billing period, or unlimited.

X-RateLimit-Quota-Remaining

Requests left in the current billing period, or unlimited.

X-RateLimit-Quota-Reset

Unix epoch seconds at which the billing period resets.

X-RateLimit-RPM-Limit

Requests allowed per minute for this resource.

X-RateLimit-RPM-Remaining

Requests left in the current one-minute window.

X-RateLimit-RPM-Reset

Unix epoch seconds at which the one-minute window resets.

Visualizationrequired
imageDatastringrequired

The rendered image as a data:<mime>;base64,… URI, usable directly as an <img src>. Typically image/png.

e.g. "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAKqCAYAAAB..."

Errors

29

Every error is JSON with a single error string unless noted. Match on the status code; the message is for humans.

400
Request body must be valid JSON.

The body could not be parsed as JSON.

400
Request body must be a JSON object.

The body is empty, or is valid JSON that is not an object (for example an array).

404
No active datasets found for this organization. Activate one via the dashboard (Dataset → Settings) or through the REST API before proceeding.

datasetIds was omitted and the organization has datasets, but none is active.

404
All requested datasets are archived. Reactivate at least one via the dashboard or REST API.

Every dataset in datasetIds is archived.

404
No datasets found for this organization. Create one via the dashboard or REST API, or pass datasetIds to use draft/archived datasets before proceeding.

The organization has no datasets at all.

404
These items could not be found: <ids>.

One or more of itemIds did not match an active item in the resolved datasets. The unmatched ids are listed, comma-separated. Check that you sent full item ids from this organization's catalogue, and the same datasetIds the agent searched.

422
A look needs at least two itemIds.

itemIds is missing, not an array, or has fewer than two distinct entries.

422
A look can hold at most 6 items.

itemIds has more than six entries.

422
userPhotoUrl must be a base64 data: URL of a JPEG, PNG or WebP image. Shopper photos are never fetched from a URL or stored.

userPhotoUrl is a web URL, a storage key, or any other type of image. Send the photo's bytes inline.

422
userPhotoUrl can be at most 3 MB.

The photo in userPhotoUrl is larger than 3 MB once decoded. Downscale it in the browser first; around 1024px on the long edge is plenty.

422
Invalid datasetIds for this organization: <ids>

One or more of datasetIds does not belong to the organization. The offending ids are listed, comma-separated.

502
Could not generate this look.

The image model returned no image or failed, including when none of the product images could be fetched. Retrying usually succeeds.

curl -X POST "https://stylor.ai/api/v2/agent/looks" \
  -H "Authorization: Bearer $STYLOR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "label": "Garden wedding",
  "itemIds": [
    "8f2c1a9e-4b7d-4c1e-9a3f-2d6b7e5c1a90",
    "1b7e33c0-9a2d-4f8e-b5c6-7d8e9f0a1b2c",
    "c4d5e6f7-0a1b-4c2d-8e9f-0a1b2c3d4e5f"
  ],
  "customInstructions": "Shirt untucked with the top button open; outdoor daylight setting.",
  "sessionId": "3b0d4a1e-6f52-4b8a-9d3c-7e2f1a0b9c8d",
  "session": {
    "surface": "widget",
    "agentVersion": "v2"
  }
}'
Response · 200
{
  "visualization": {
    "imageData": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAKqCAYAAAB..."
  }
}