FLAM

Assets

10 Assets routes on the FLAM API: The house's captured assets, newest first; Stream one asset's bytes from R2 (owner-gated); Rename, classify, tag or.

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/assets

The house's captured assets, newest first

The body is { assets: [...] }, not a bare array — it was documented as a bare array until task #40 and never was one.

Parameters

InNameTypeRequiredNotes
queryfolderIdstringnoNarrow to one collection

Responses

StatusMeaning
200Asset list
401No valid session

200 returns:

{
  "assets": [
    {
      "id": "string",
      "name": "string",
      "sku": "string",
      "kind": "clothes",
      "url": "string",
      "folderId": "string",
      "groupId": "string",
      "mime": "string",
      "tool": "string",
      "createdAt": "2026-07-27T09:00:00.000Z"
    }
  ]
}

Call it

curl -X GET "https://api.flam.fashion/api/toolkit/assets" \
  -H "Authorization: Bearer $FLAM_API_KEY"

GET /api/toolkit/assets/{id}

Stream one asset's bytes from R2 (owner-gated)

Parameters

InNameTypeRequiredNotes
pathidstringyes

Responses

StatusMeaning
200The image bytes (content-type from the asset row)
401No valid session
403Not the owner
404Unknown or deleted

Call it

curl -X GET "https://api.flam.fashion/api/toolkit/assets/{id}" \
  -H "Authorization: Bearer $FLAM_API_KEY"

PATCH /api/toolkit/assets/{id}

Rename, classify, tag or move one piece

An explicit folderId: null moves the piece back to the root. kind is stored as the reserved kind: tag and sku as the sku: tag, so both can be cleared with null. An empty patch is a 200 no-op, not an error.

Parameters

InNameTypeRequiredNotes
pathidstringyes

Request bodyapplication/json (required)

FieldTypeRequiredNotes
namestringno
skustring | nullno
kind"clothes" | "accessory" | "jewelry" | "model" | "background"no
folderIdstring | nullno
{
  "name": "string",
  "sku": "string",
  "kind": "clothes",
  "folderId": "string"
}

Responses

StatusMeaning
200The updated asset
400BAD_BODY / BAD_KIND / BAD_SKU / BAD_FOLDER
401No valid session
404Unknown or foreign asset

200 returns:

{
  "asset": {
    "id": "string",
    "name": "string",
    "sku": "string",
    "kind": "clothes",
    "url": "string",
    "folderId": "string",
    "groupId": "string",
    "mime": "string",
    "tool": "string",
    "createdAt": "2026-07-27T09:00:00.000Z"
  }
}

Call it

curl -X PATCH "https://api.flam.fashion/api/toolkit/assets/{id}" \
  -H "Authorization: Bearer $FLAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","sku":"string","kind":"clothes","folderId":"string"}'

GET /api/toolkit/assets/{id}/file

Stream one asset's bytes (the contract serving route)

Where every url in a list response points. Owner-gated, and a FOREIGN id answers 404, never 403 — this route never confirms that someone else's asset exists. (The legacy /api/toolkit/assets/{id} answers 403 for a foreign id; it is kept only for old links.)

Parameters

InNameTypeRequiredNotes
pathidstringyes

Responses

StatusMeaning
200The image bytes (Cache-Control private, max-age=3600; ETag from R2)
401No valid session
404Unknown

Call it

curl -X GET "https://api.flam.fashion/api/toolkit/assets/{id}/file" \
  -H "Authorization: Bearer $FLAM_API_KEY"

POST /api/toolkit/assets/group

Stamp a fresh shared group onto a set of pieces

Writes group:<uuid> onto every named asset, REPLACING any prior group (re-grouping moves a piece). All-or-nothing: every id must be one of the caller's live assets or nothing is written.

Request bodyapplication/json (required)

FieldTypeRequiredNotes
assetIdsstring[]yesUnique, non-empty. Duplicates are rejected.
namestringnoAccepted and currently unused
{
  "assetIds": [
    "string"
  ],
  "name": "string"
}

Responses

StatusMeaning
201The new group id
400BAD_BODY / BAD_ASSET_IDS
401No valid session
404One of the ids is unknown

201 returns:

{
  "groupId": "string"
}

Call it

curl -X POST "https://api.flam.fashion/api/toolkit/assets/group" \
  -H "Authorization: Bearer $FLAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"assetIds":["string"],"name":"string"}'

POST /api/toolkit/assets/upload

Hang one image in the house library (multipart)

Bytes → R2, row → assets. The upload itself is FREE. SMART UPLOAD — classify=1 is an OPT-IN read priced at 1 token per image (the describe-item classifier, run in-process after the row is written). It files the piece into its wardrobe bucket (kind) and gives it a human name — "IMG_2489.jpeg" becomes "white ribbed lace trim henley", a model collage comes back kind=model. Anything you state yourself wins: a supplied name/kind is never overwritten, and sku is your own code — it is never invented. Omit classify and nothing is read and nothing is charged. A failed read never loses the upload and never charges: 201 with the asset unclassified and classify.ok=false carrying the reason (INSUFFICIENT_TOKENS, AI_NOT_CONFIGURED, AI_FAILED, …).

Request bodymultipart/form-data (required)

FieldTypeRequiredNotes
filefileyes
folderIdstringnoTarget collection; omit for the root
namestringnoYour own label; wins over the smart read
kind"clothes" | "accessory" | "jewelry" | "model" | "background"noYour own wardrobe bucket; wins over the smart read
skustringnoThe brand's own code
classify"1" | "true" | "on" | "0"noOpt in to the 1-token smart read

Responses

StatusMeaning
201The hung asset (+ classify when the read was requested)
400NO_FILE / UNSUPPORTED_TYPE / EMPTY_FILE / BAD_KIND / BAD_SKU / BAD_FORM
401No valid session
404Unknown or foreign folderId
413IMAGE_TOO_LARGE (12 MB cap)

201 returns:

{
  "asset": {
    "id": "string",
    "name": "string",
    "sku": "string",
    "kind": "clothes",
    "url": "string",
    "folderId": "string",
    "groupId": "string",
    "mime": "string",
    "tool": "string",
    "createdAt": "2026-07-27T09:00:00.000Z"
  },
  "classify": {
    "ok": true,
    "nameEn": "string",
    "kind": "string",
    "error": "string",
    "tokens": 0
  }
}

Call it

curl -X POST "https://api.flam.fashion/api/toolkit/assets/upload" \
  -H "Authorization: Bearer $FLAM_API_KEY" \
  -F "[email protected]" \
  -F "folderId=<folderId>" \
  -F "name=<name>" \
  -F "kind=<kind>" \
  -F "sku=<sku>" \
  -F "classify=<classify>"

GET /api/toolkit/backgrounds

The whole library a look can stand on

Two sources, one call — the house's curated grounds (static, shipped with the code) and this director's own scenes (assets tagged kind:background, uploaded through /api/toolkit/assets/upload). Only the PUBLIC projection of a ground crosses the wire; the prompt clause it contributes stays server-side.

Responses

StatusMeaning
200Grounds + the house's own sets
401No valid session

200 returns:

{
  "grounds": [
    {
      "id": "string",
      "kind": "string",
      "name": "string",
      "note": "string",
      "tone": "string",
      "previewUrl": "string"
    }
  ],
  "scenes": [
    {
      "id": "string",
      "name": "string",
      "url": "string",
      "createdAt": "2026-07-27T09:00:00.000Z"
    }
  ]
}

Call it

curl -X GET "https://api.flam.fashion/api/toolkit/backgrounds" \
  -H "Authorization: Bearer $FLAM_API_KEY"

GET /api/toolkit/folders

Every collection in the house, flat

Oldest first. The client builds the tree from parentId.

Responses

StatusMeaning
200The folder list
401No valid session

200 returns:

{
  "folders": [
    {
      "id": "string",
      "name": "string",
      "parentId": "string",
      "createdAt": "2026-07-27T09:00:00.000Z"
    }
  ]
}

Call it

curl -X GET "https://api.flam.fashion/api/toolkit/folders" \
  -H "Authorization: Bearer $FLAM_API_KEY"

POST /api/toolkit/folders

Create a collection

Request bodyapplication/json (required)

FieldTypeRequiredNotes
namestringyes
parentIdstring | nullnoNest under an owned folder
{
  "name": "string",
  "parentId": "string"
}

Responses

StatusMeaning
201The created folder
400BAD_BODY / NAME_REQUIRED
401No valid session
404Unknown or foreign parentId

201 returns:

{
  "folder": {
    "id": "string",
    "name": "string",
    "parentId": "string",
    "createdAt": "2026-07-27T09:00:00.000Z"
  }
}

Call it

curl -X POST "https://api.flam.fashion/api/toolkit/folders" \
  -H "Authorization: Bearer $FLAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string","parentId":"string"}'

PATCH /api/toolkit/folders/{id}

Rename a collection

A no-op rename (same name, or none supplied) still answers 200 with the folder.

Parameters

InNameTypeRequiredNotes
pathidstringyes

Request bodyapplication/json (required)

FieldTypeRequiredNotes
namestringno
{
  "name": "string"
}

Responses

StatusMeaning
200The folder
400BAD_BODY
401No valid session
404Unknown or foreign id

200 returns:

{
  "folder": {
    "id": "string",
    "name": "string",
    "parentId": "string",
    "createdAt": "2026-07-27T09:00:00.000Z"
  }
}

Call it

curl -X PATCH "https://api.flam.fashion/api/toolkit/folders/{id}" \
  -H "Authorization: Bearer $FLAM_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"string"}'