Create outfit compositions
/v1/outfit/compositionsRetired. This endpoint answers
410 Gonefor every API caller. It is documented for reference only; new integrations should render looks through the v2 agent API instead.
Takes the products the stylist recommended in a chat and turns them into complete outfits: a language model picks coherent combinations from the most recent recommendation, then an image model renders each combination as a single composed look (optionally on the shopper's own photo).
What it needs from the chat
The chat identified by chatId must belong to your organization and its
most recent assistant message must contain at least one search slot with
results — that is what "the most recent recommendation" means. Slots from
earlier turns are also passed to the model as context and may be drawn
on, but the latest turn is the primary source. Up to five products per
slot are considered.
How many outfits you get
count asks for 1–10 outfits. It is then clamped to what the latest
recommendation can actually support: the product of
min(results in slot, 3) over the latest slots, capped at 10 and never
below 1. A single-slot recommendation with two results therefore yields
at most two outfits however large count was. Individual renders can
fail; those are dropped, so the response may contain fewer outfits than
the clamped count. The request only fails when none succeeds.
Images
Each render is uploaded to Stylor's image storage and returned as an
imageUrl. When the upload fails the image is returned inline instead as
a compressed JPEG data URL (imageSource: compressed), and if even that
fails, as the original PNG data URL (imageSource: original). Renders
use the 9:16 aspect ratio by default; override it through
preferences.aspectRatio. At most three product photos (two when a user
photo is supplied) are handed to the image model; the remaining products
are described in text.
JSON vs. streaming
By default the call blocks until every outfit has been selected and
rendered, then returns everything at once. Send stream: true to receive
a text/event-stream instead: each outfit is announced as soon as the
model has chosen it, its image follows as soon as it is rendered, and a
done event carries the summary. Validation and quota errors are still
returned as JSON with the usual status code before the stream opens;
failures after that arrive as error events on the stream with HTTP
status 200.
Persistence
Every successful outfit is stored with a compositionId (the id in
the response) under your organization and the chat. When slotId is
given, the ids are also written to that slot's compositions list in the
chat, so they can be retrieved with the conversation. A slot update that
fails does not fail the request.
Request body
application/jsonrequiredId of a chat owned by your organization whose latest assistant message contains search slots with results.
Outfits to generate. Parsed as an integer ("3" and 3.7 both become 3); values outside 1–10 are rejected. Then clamped to the number of distinct combinations the latest recommendation supports.
Optional photo of the shopper to dress. A data:image/…;base64,…
URL or a publicly fetchable https image URL. When present, the
render composes the outfit on this person and only two product
photos (preferring flat-lay shots) are passed to the image model.
Hints passed to the models. Stored alongside each composition. Unknown keys are kept but not read.
Presented to the outfit-selection model as the shopper's gender. Free text; not validated.
Free-text style direction for the outfit-selection model (for example relaxed weekend brunch).
Aspect ratio of the rendered image, as accepted by the image model (for example 9:16, 1:1, 3:4).
Optional id of a slot in the chat's latest assistant message. The generated composition ids are written to that slot's compositions list.
Send true to receive a text/event-stream instead of a single JSON body.
Response
stream: true) the body is a
text/event-stream; see the stream events below.
application/jsonOne entry per outfit that rendered successfully.
Composition id. Also stored on the chat slot when slotId was supplied.
Where to load the rendered image. An https://stylor.ai/api/v1/image/… URL when imageSource is cdn; otherwise a data:image/…;base64,… URL.
cdn — uploaded and served by URL; compressed — upload failed, inline JPEG (max 800px wide, quality 80); original — compression also failed, inline original PNG.
cdncompressedoriginalJSON mode only. The uncompressed render as a data:image/…;base64,…
URL, always included regardless of imageSource. This makes JSON
responses large; prefer imageUrl and consider streaming mode,
which omits this field.
Same text as combination.reasoning.
Number of outfits returned (renders that failed are not counted).
Wall-clock time for the whole request, in milliseconds.
Whether userPhotoUrl was supplied.
Outfits whose image was uploaded (imageSource of cdn).
Outfits returned as inline compressed JPEG.
Outfits returned as the inline original image.
text/event-streamSSE frames of the form event: <name> / data: <json> separated by a blank line. See the stream events for each payload.
Stream events
6Each frame is event: <name> followed by data: <json> and a blank line. Events are listed in the order they normally arrive.
preparingSent immediately, before any lookup, so a client can lay out placeholder cards. count is the validated (not yet clamped) request count.
{
"count": 3
}combinationOne outfit has been selected. index is its 0-based position and id the composition id; the matching visualization (or visualization_error) will carry the same id and index. Combinations arrive in order; images do not.
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"index": 0,
"combination": {
"name": "Weekend Neutrals",
"description": "A soft, tonal outfit for a relaxed brunch.",
"reasoning": "The cream knit and straight-leg jeans share a relaxed silhouette.",
"items": [
{
"slotId": "3f2a1b0c-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
"slotType": "top",
"productId": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f",
"confidence": 0.92
}
]
}
}visualizationThe render for one combination is ready. Renders run concurrently, so these can arrive in any order and may interleave with later combination events. Unlike the JSON response, no inline imageData is included; imageUrl is a data URL when imageSource is not cdn.
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"index": 0,
"imageUrl": "https://stylor.ai/api/v1/image/images/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d.png",
"imageSource": "cdn",
"reasoning": "The cream knit and straight-leg jeans share a relaxed silhouette.",
"combination": {
"name": "Weekend Neutrals",
"description": "A soft, tonal outfit for a relaxed brunch.",
"reasoning": "The cream knit and straight-leg jeans share a relaxed silhouette.",
"items": [
{
"slotId": "3f2a1b0c-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
"slotType": "top",
"productId": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f",
"confidence": 0.92
}
]
}
}visualization_errorThe render for one combination failed. The outfit is dropped from the saved set; the stream continues.
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"index": 1,
"error": "Failed to generate this visualization"
}doneEvery render has settled and the surviving outfits are saved. metadata matches the JSON response. The stream closes after this event.
{
"metadata": {
"totalCombinations": 3,
"generationTime": 21870,
"usedUserPhoto": false,
"cdnUploads": 3,
"compressedImages": 0,
"originalImages": 0
}
}errorA fatal failure; the stream closes after this event and no done
follows. error is one of Chat not found or access denied,
No outfit items found in most recent recommendation,
Failed to generate outfit combinations,
Failed to generate any visualizations, or
Something went wrong generating your outfit visualizations. Let's try that again.
for any unexpected failure.
{
"error": "No outfit items found in most recent recommendation"
}Errors
26Every error is JSON with a single error string unless noted. Match on the status code; the message is for humans.
Request body must be valid JSON.The request body could not be parsed as JSON. Checked before authentication.
Request body must be a JSON object.The request body is empty, or parsed to something other than a JSON object. Checked before authentication.
Chat not found or access deniedNo chat with that chatId belongs to your organization. Streaming mode: sent as an error event.
This endpoint has been retired (v1/outfit/compositions).Always, for API callers. This check runs before authentication and consumes no quota.
chatId is requiredchatId is missing or not a string. In streaming mode this is returned as JSON before the stream opens.
count must be between 1 and 10count does not parse as an integer from 1 to 10. In streaming mode this is returned as JSON before the stream opens.
No outfit items found in most recent recommendationThe chat's latest assistant message has no search slot with results. Streaming mode: sent as an error event.
Failed to generate outfit combinationsThe language model returned no usable combinations. Streaming mode: sent as an error event.
Failed to generate any visualizationsEvery image render failed (for example no product had a usable photo). Streaming mode: sent as an error event.
curl -X POST "https://stylor.ai/api/v1/outfit/compositions" \
-H "Authorization: Bearer $STYLOR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chatId": "8b4d3f6e-2c1a-4f0e-9d7b-5a6c1e2f3a4b",
"count": 3
}'{
"visualizations": [
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"imageUrl": "https://stylor.ai/api/v1/image/images/a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d.png",
"imageSource": "cdn",
"imageData": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"reasoning": "The cream knit and straight-leg jeans share a relaxed silhouette, and the white sneakers keep the whole look light.",
"combination": {
"name": "Weekend Neutrals",
"description": "A soft, tonal outfit for a relaxed brunch.",
"reasoning": "The cream knit and straight-leg jeans share a relaxed silhouette, and the white sneakers keep the whole look light.",
"items": [
{
"slotId": "3f2a1b0c-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
"slotType": "top",
"productId": "9f1c2d3e-4b5a-4c6d-8e7f-0a1b2c3d4e5f",
"confidence": 0.92
},
{
"slotId": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
"slotType": "bottom",
"productId": "2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f",
"confidence": 0.88
},
{
"slotId": "0e1f2a3b-4c5d-4e6f-8a7b-9c0d1e2f3a4b",
"slotType": "shoes",
"productId": "5e6f7a8b-9c0d-4e1f-8a2b-3c4d5e6f7a8b",
"confidence": 0.81
}
]
}
}
],
"metadata": {
"totalCombinations": 1,
"generationTime": 18432,
"usedUserPhoto": false,
"cdnUploads": 1,
"compressedImages": 0,
"originalImages": 0
}
}