Lookbook
9 Lookbook routes on the FLAM API: The house's looks, newest first (50); Create a look from the director's three choices; One look, whole — selections.
Base URL https://api.flam.fashion. Send Authorization: Bearer flam_sk_… on every call; a handful of routes are session-only and say so. How keys and roles work.
GET /api/toolkit/lookbook/looks
The house's looks, newest first (50)
Responses
| Status | Meaning |
|---|---|
200 | The looks |
401 | No valid session |
200 returns:
{
"looks": [
{
"id": "string",
"organizationId": "string",
"createdByUserId": "string",
"brandId": "string",
"name": "string",
"modelAssetId": "string",
"backgroundAssetId": "string",
"itemAssetIds": [
{
"assetId": null,
"role": null
}
],
"preset": {
"aesthetic": "string",
"background": {}
},
"status": "draft",
"lookBaseAssetId": "string",
"lookBaseJobId": "string",
"variations": [
{}
],
"createdAt": "2026-07-27T09:00:00.000Z",
"updatedAt": "2026-07-27T09:00:00.000Z"
}
]
}Call it
curl -X GET "https://api.flam.fashion/api/toolkit/lookbook/looks" \
-H "Authorization: Bearer $FLAM_API_KEY"POST /api/toolkit/lookbook/looks
Create a look from the director's three choices
Model + items + background, dressed by an aesthetic preset. SELECTIONS ONLY — nothing develops and nothing is charged here. Every referenced asset is owner-gated up front, so a foreign id writes nothing.
Request body — application/json (required)
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | — |
modelAssetId | string | yes | — |
itemAssetIds | object[] | yes | — |
background | object | yes | { kind: "preset", value } or { kind: "asset", assetId } |
aesthetic | string | yes | A key of the composer's AESTHETIC_PRESETS |
brandId | string | null | no | — |
{
"name": "string",
"modelAssetId": "string",
"itemAssetIds": [
{
"assetId": "string",
"role": "string"
}
],
"background": {
"kind": "preset",
"value": "string",
"assetId": "string"
},
"aesthetic": "string",
"brandId": "string"
}Responses
| Status | Meaning |
|---|---|
201 | The draft look |
400 | BAD_BODY / NAME_REQUIRED / MODEL_REQUIRED / ITEMS_REQUIRED / TOO_MANY_ITEMS / BAD_ITEM / BAD_BACKGROUND / BAD_AESTHETIC — the rejection carries the legal vocabulary (roles / presets) |
401 | No valid session |
404 | ASSET_NOT_FOUND — a referenced asset is unknown |
201 returns:
{
"look": {
"id": "string",
"organizationId": "string",
"createdByUserId": "string",
"brandId": "string",
"name": "string",
"modelAssetId": "string",
"backgroundAssetId": "string",
"itemAssetIds": [
{
"assetId": "string",
"role": "string"
}
],
"preset": {
"aesthetic": "string",
"background": {}
},
"status": "draft",
"lookBaseAssetId": "string",
"lookBaseJobId": "string",
"variations": [
{}
],
"createdAt": "2026-07-27T09:00:00.000Z",
"updatedAt": "2026-07-27T09:00:00.000Z"
}
}Call it
curl -X POST "https://api.flam.fashion/api/toolkit/lookbook/looks" \
-H "Authorization: Bearer $FLAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"string","modelAssetId":"string","itemAssetIds":[{"assetId":"string","role":"string"}],"background":{"kind":"preset","value":"string","assetId":"string"},"aesthetic":"string","brandId":"string"}'GET /api/toolkit/lookbook/looks/{id}
One look, whole — selections, lock state, the variation batch
Each variation is joined with its generation_job, so status / resultAssetId / error come back per frame. lockDevelop is the newest lock-stage job, which is what lets a reloaded wizard rehydrate the loop.
Parameters
| In | Name | Type | Required | Notes |
|---|---|---|---|---|
| path | id | string | yes | — |
Responses
| Status | Meaning |
|---|---|
200 | The look + its frames |
401 | No valid session |
404 | NOT_FOUND |
200 returns:
{
"look": {
"id": "string",
"organizationId": "string",
"createdByUserId": "string",
"brandId": "string",
"name": "string",
"modelAssetId": "string",
"backgroundAssetId": "string",
"itemAssetIds": [
{
"assetId": "string",
"role": "string"
}
],
"preset": {
"aesthetic": "string",
"background": {}
},
"status": "draft",
"lookBaseAssetId": "string",
"lookBaseJobId": "string",
"variations": [
{}
],
"createdAt": "2026-07-27T09:00:00.000Z",
"updatedAt": "2026-07-27T09:00:00.000Z"
},
"variations": [
{
"key": "string",
"framing": "string",
"jobId": "string",
"assetId": "string",
"locked": true,
"status": "string",
"error": "string"
}
],
"lockDevelop": {
"id": "string",
"status": "string",
"resultAssetId": "string",
"error": "string"
}
}Call it
curl -X GET "https://api.flam.fashion/api/toolkit/lookbook/looks/{id}" \
-H "Authorization: Bearer $FLAM_API_KEY"POST /api/toolkit/lookbook/looks/{id}/develop-lock
Develop the LOOK's lock frame
Composes the lock frame server-side (the prompt never enters the jobs DB) and runs it through the spine as ONE job. Draft looks only. Reserves the whole cost — tier plus any restoration pass the destination forces — before anything is enqueued. The finished resultUrl is the frame as DEVELOPED: the tier's pixels at the destination's shape. It is not resampled to output.width × output.height — cut it yourself, which is a pure downscale for every place except the two A-series print sizes.
Parameters
| In | Name | Type | Required | Notes |
|---|---|---|---|---|
| path | id | string | yes | — |
Request body — application/json
| Field | Type | Required | Notes |
|---|---|---|---|
quality | "1k" | "2k" | "4k" | no | The tier the frame develops at — 1,024 / 2,048 / 4,096 px on the long edge. |
output | OutputDestination | no | WHERE the frame is going. Omit and the frame simply develops at the tier. A named place carries its own exact pixels; "custom" carries yours. The frame is COMPOSED for that shape and developed at the tier's pixels — the response is not resampled to width × height, so cut it yourself (a pure downscale for every place except the two A-series print sizes, which are composed at 2:3 and cost a 5.7% trim). Never upscale a frame that came back smaller than the place asked for: that is invented detail, and the house sells it only as a priced restoration pass on the 4K tier. |
idempotencyKey | string | no | Makes one gesture safe to retry. Generated when omitted. |
{
"quality": "2k",
"output": {
"destination": "web-tile",
"width": 0,
"height": 0
},
"idempotencyKey": "string"
}Responses
| Status | Meaning |
|---|---|
202 | Job queued (or the existing job on an idempotent replay) |
400 | BAD_BODY | UNKNOWN_DESTINATION | BAD_DIMENSIONS | OUTPUT_TOO_LARGE | QUALITY_TOO_LOW_FOR_OUTPUT — the body carries a plain-language detail naming the pixels ("1K develops at 1,024 px — an Instagram post needs 1,080."). |
401 | No valid session |
402 | INSUFFICIENT_TOKENS — body includes need + spendable |
404 | NOT_FOUND |
409 | DEVELOP_IN_FLIGHT | LOOK_LOCKED |
202 returns:
{
"jobId": "string",
"status": "string"
}Call it
curl -X POST "https://api.flam.fashion/api/toolkit/lookbook/looks/{id}/develop-lock" \
-H "Authorization: Bearer $FLAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"quality":"2k","output":{"destination":"web-tile","width":0,"height":0},"idempotencyKey":"string"}'POST /api/toolkit/lookbook/looks/{id}/lock
Freeze the Look Base
PROVENANCE IS REQUIRED — the asset must be the captured result of one of THIS look's develop jobs, otherwise 422. Locking also records lineage: the Look Base's parent becomes the model collage.
Parameters
| In | Name | Type | Required | Notes |
|---|---|---|---|---|
| path | id | string | yes | — |
Request body — application/json (required)
| Field | Type | Required | Notes |
|---|---|---|---|
assetId | string | yes | — |
{
"assetId": "string"
}Responses
| Status | Meaning |
|---|---|
200 | The locked look |
400 | BAD_BODY / ASSET_REQUIRED |
401 | No valid session |
404 | NOT_FOUND |
409 | DEVELOP_IN_FLIGHT — the look is mid-batch |
422 | NOT_A_LOOK_FRAME — that asset did not develop from this look |
200 returns:
{
"look": {
"id": "string",
"organizationId": "string",
"createdByUserId": "string",
"brandId": "string",
"name": "string",
"modelAssetId": "string",
"backgroundAssetId": "string",
"itemAssetIds": [
{
"assetId": "string",
"role": "string"
}
],
"preset": {
"aesthetic": "string",
"background": {}
},
"status": "draft",
"lookBaseAssetId": "string",
"lookBaseJobId": "string",
"variations": [
{}
],
"createdAt": "2026-07-27T09:00:00.000Z",
"updatedAt": "2026-07-27T09:00:00.000Z"
}
}Call it
curl -X POST "https://api.flam.fashion/api/toolkit/lookbook/looks/{id}/lock" \
-H "Authorization: Bearer $FLAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"assetId":"string"}'POST /api/toolkit/lookbook/looks/{id}/unlock
The explicit intent required before re-developing a locked look
Nothing is destroyed — the look-base fields stay and the next lock supersedes them. Already a draft ⇒ 200, unchanged. No body.
Parameters
| In | Name | Type | Required | Notes |
|---|---|---|---|---|
| path | id | string | yes | — |
Responses
| Status | Meaning |
|---|---|
200 | The draft look |
401 | No valid session |
404 | NOT_FOUND |
409 | DEVELOP_IN_FLIGHT |
200 returns:
{
"look": {
"id": "string",
"organizationId": "string",
"createdByUserId": "string",
"brandId": "string",
"name": "string",
"modelAssetId": "string",
"backgroundAssetId": "string",
"itemAssetIds": [
{
"assetId": "string",
"role": "string"
}
],
"preset": {
"aesthetic": "string",
"background": {}
},
"status": "draft",
"lookBaseAssetId": "string",
"lookBaseJobId": "string",
"variations": [
{}
],
"createdAt": "2026-07-27T09:00:00.000Z",
"updatedAt": "2026-07-27T09:00:00.000Z"
}
}Call it
curl -X POST "https://api.flam.fashion/api/toolkit/lookbook/looks/{id}/unlock" \
-H "Authorization: Bearer $FLAM_API_KEY"POST /api/toolkit/lookbook/looks/{id}/variations
Fan the LOOK out into its variations
One job per chosen variation, with smart refs per the library (a medium shot drops the shoes; a back shot keeps the model). The look must be locked. All-or-nothing reserve across the whole batch: the first shortfall releases every hold already taken. An output destination applies to EVERY frame, so its cost is reserved per frame up front — and every resultUrl comes back as developed (the tier's pixels at that destination's shape), not resampled to its exact width × height.
Parameters
| In | Name | Type | Required | Notes |
|---|---|---|---|---|
| path | id | string | yes | — |
Request body — application/json (required)
{
"quality": "2k",
"output": {
"destination": "web-tile",
"width": 0,
"height": 0
},
"idempotencyKey": "string",
"keys": [
"string"
]
}Responses
| Status | Meaning |
|---|---|
202 | One queued job per requested key |
400 | BAD_BODY | KEYS_REQUIRED | TOO_MANY_FRAMES | UNKNOWN_VARIATION | UNKNOWN_DESTINATION | BAD_DIMENSIONS | OUTPUT_TOO_LARGE | QUALITY_TOO_LOW_FOR_OUTPUT |
401 | No valid session |
402 | INSUFFICIENT_TOKENS — body includes need + spendable |
404 | NOT_FOUND |
409 | DEVELOP_IN_FLIGHT | LOCK_REQUIRED |
202 returns:
{
"jobs": [
{
"key": "string",
"jobId": "string"
}
]
}Call it
curl -X POST "https://api.flam.fashion/api/toolkit/lookbook/looks/{id}/variations" \
-H "Authorization: Bearer $FLAM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"quality":"2k","output":{"destination":"web-tile","width":0,"height":0},"idempotencyKey":"string","keys":["string"]}'GET /api/toolkit/lookbook/templates
Shot templates — the house's built-ins plus the caller's own
Built-ins are the rows with organization_id IS NULL; they list first.
Responses
| Status | Meaning |
|---|---|
200 | The templates, each with its shot count |
401 | No valid session |
200 returns:
{
"templates": [
{
"id": "string",
"name": "string",
"slots": {},
"shot_count": 0,
"created_at": "2026-07-27T09:00:00.000Z",
"updated_at": "2026-07-27T09:00:00.000Z"
}
]
}Call it
curl -X GET "https://api.flam.fashion/api/toolkit/lookbook/templates" \
-H "Authorization: Bearer $FLAM_API_KEY"GET /api/toolkit/lookbook/templates/{id}
One template and its shots, in order
Parameters
| In | Name | Type | Required | Notes |
|---|---|---|---|---|
| path | id | string | yes | — |
Responses
| Status | Meaning |
|---|---|
200 | The template + its shots |
400 | id required |
401 | No valid session |
404 | NOT_FOUND — unknown |
200 returns:
{
"template": {},
"shots": [
{
"id": "string",
"type": "string",
"framing": "string",
"pose": "string",
"expression": "string",
"sort_order": 0
}
]
}Call it
curl -X GET "https://api.flam.fashion/api/toolkit/lookbook/templates/{id}" \
-H "Authorization: Bearer $FLAM_API_KEY"Jobs
7 Jobs routes on the FLAM API: The house's develop RUNS, newest first; Stop a whole run — honestly; Reconnect backfill — jobs newer than an eventSeq.
Factory
4 Factory routes on the FLAM API: What the house INTENDS, before a token moves; The one confirm — create the batch of draft looks; The house's standing.