# Fashio API — full reference for LLMs and coding agents Fashio generates publish-ready e-commerce fashion photos with AI. A merchant (or a developer integrating on a merchant's behalf) uploads a garment photo, picks an AI model and a venue/pose, and gets back on-model product shots — the same pipeline behind the Fashio mobile app and the fashiolabs.com web dashboard. This document is written for an LLM (Claude, GPT, or a coding agent) to read once and be able to write correct integration code without further lookups. If you are an AI assistant helping a developer integrate Fashio, this is the only file you need. ## What this API is for - Turning a single garment/product photo into on-model e-commerce photography. - Batch product photo packs (flat-lay + on-model shots) for a catalog. - Background removal, upscaling, reframing/cropping to a target aspect ratio. - Turning a still photo into a short product video (image-to-video). - Jewelry-specific on-model shots (ring/necklace/earring/bracelet). ## Base URL and authentication Base URL: https://api.fashiolabs.com Header: Authorization: Bearer fio_live_. Every request needs this header. There is no separate "test mode" — a key authenticates as a real Fashio account and every generation deducts diamonds (Fashio's credit unit) from that account's balance, exactly as using the app would. A user creates their own key at fashiolabs.com → Profile → API Keys; it is shown once at creation time and cannot be recovered afterwards (only revoked and replaced). Every key has a daily request cap. Exceeding it returns `429` with `{"success": false, "error": "Daily request cap (N) reached for this key."}`. All error responses share the same shape: `{"success": false, "error": ""}`. All success responses include `"success": true`. ## The end-to-end flow 1. `POST /v1/uploads` — send a garment/product photo, get back a URL. 2. (Optional) `GET /v1/fashion-models`, `GET /v1/venues`, `GET /v1/poses` — browse the catalog to pick a model/venue/pose id. Skip this if the tool doesn't need one (e.g. `remove_background`), or if you already have specific ids. 3. `POST /v1/generations` — start a job with `toolId` + the URLs/ids you have. Returns immediately with `status: "processing"` and a job `id`. 4. `GET /v1/generations/{id}` — poll (e.g. every 2s) until `status` is `"completed"` or `"failed"`. On completion, `resultUrls` holds the output image(s)/video. ```bash # 1. Upload the garment photo curl https://api.fashiolabs.com/v1/uploads \ -H "Authorization: Bearer $FASHIO_API_KEY" \ -H "Content-Type: image/jpeg" \ --data-binary @garment.jpg # => {"success":true,"id":"...","url":"https://firebasestorage.../garment.jpg"} # 2. Start a virtual try-on generation curl https://api.fashiolabs.com/v1/generations \ -H "Authorization: Bearer $FASHIO_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "toolId": "virtual_model", "images": { "fashion_model": "6a2f811f-0465-4c70-92aa-2434765441f9", "garment_photo": "https://firebasestorage.../garment.jpg", "venue": "pure_white" }, "pose": "contrapposto_elegance" }' # => {"success":true,"id":"AbCdEf123","status":"processing"} # 3. Poll for the result curl https://api.fashiolabs.com/v1/generations/AbCdEf123 \ -H "Authorization: Bearer $FASHIO_API_KEY" # => {"success":true,"id":"AbCdEf123","status":"completed","resultUrls":["https://..."]} ``` ## Endpoints ### GET /v1/models Lists every valid `toolId` for `POST /v1/generations`, with its input shape and a fallback diamond price (the real price is resolved per-request from the current catalog and may be marginally different). => {"success":true,"models":[{"id":"virtual_model","inputShape":"model_garment","promptMode":"assembled","fallbackPriceDiamonds":4}, ...]} ### GET /v1/fashion-models?gender=&limit= Selectable AI person models. `gender` is `male` or `female` (omit for both). Each model's `id` is what you pass as `images.fashion_model` in a generation (or you can pass any image URL directly instead of a catalog id, for tools that accept it). ### GET /v1/venues?limit= Selectable backgrounds/environments. Each venue's `id` is what you pass as `images.venue`. ### GET /v1/poses?type=&limit= Selectable poses. Omit `type` for the default (non-jewelry) pose set; pass `type=ring` (or `necklace`/`earring`/`bracelet`) for jewelry-specific poses. Each pose's `id` is what you pass as `pose`. ### POST /v1/uploads Body: raw image bytes, `Content-Type: image/jpeg` / `image/png` / `image/webp`. Max 8 MB. Returns `{"success":true,"id":"","url":""}`. Pass that `url` into any `images.*` field of a generation. 413 if too large, 415 if not a recognized image format (checked by file signature, not by the Content-Type header you send). ### POST /v1/generations Body: JSON, see "Request body" below. Deducts diamonds immediately and queues the job; returns `202` with `{"success":true,"id":"","status":"processing"}`. 400 for an unknown `toolId` or a missing required image (nothing is charged in that case). 402 if the account's diamond balance is below the tool's price. ### GET /v1/generations/{id} Poll this until `status` is no longer `"processing"`. => {"success":true,"id":"...","status":"completed","resultUrls":["https://..."],"errorMessage":null} => {"success":true,"id":"...","status":"failed","resultUrls":[],"errorMessage":"..."} 404 if the id doesn't exist, or belongs to a different account than the key used. ## Request body for POST /v1/generations ``` { "toolId": string, // required — see GET /v1/models "images": { // keys depend on toolId, see table below "": "" | ["", ...] }, "pose": string, // optional — a pose id from GET /v1/poses "shotType": string, // pro_studio only "stylePreset": string, // pro_studio only "customPrompt": string, // free-text note; REQUIRED for photo_edit "motionPrompt": string, // ai_videos only — describes the motion "ratio": string, // "1:1" | "9:16" | "16:9" | "4:3" | "3:4" | "4:5" | "auto" "duration": number, // ai_videos only, seconds (default 5) "targetRatio": string, // photo_reframe only — the output aspect ratio "jewelryType": string, // jewelry_on_model only — ring|necklace|earring|bracelet "backgroundColor": string // jewelry_on_model only, optional solid studio background } ``` `images.fashion_model` and `images.venue` accept EITHER a catalog id (from `/v1/fashion-models` or `/v1/venues`) OR a direct image URL. Every other image field must be a URL — get one from `/v1/uploads` or your own hosting. ### Per-tool `images` requirements | toolId | Required images | Notes | |------------------------|-----------------------------------------------|-------| | `virtual_model` | `fashion_model`, `garment_photo` | optional `garment_photos[]`, `venue`, `pose`, `customPrompt` | | `outfit_photo` | `fashion_model`, `garment_photos[]` | batch version of virtual_model; optional `venue`, `pose` | | `pro_studio` | `fashion_model`, `garment_photos[]` | needs `shotType` + `stylePreset` | | `jewelry_on_model` | `jewelry_image` or `jewelry_images[]` | optional `fashion_model`, needs `jewelryType`; optional `pose`, `backgroundColor` | | `clothing_ecom_pack` | `user_photo` | optional `fashion_model`; fans out to multiple shots | | `jewelry_ecom_pack` | `user_photo` | optional `fashion_model`; fans out to multiple shots | | `ai_videos` | `user_photo` | needs `motionPrompt`; optional `duration` | | `model_to_flat_lay` | `user_photo` | mannequin/on-model photo → flat lay | | `amateur_to_pro` | `user_photo` | deterministic retouch, no prompt needed | | `pose_angle_switch` | `user_photo` | needs `pose` | | `model_swap` | `user_photo`, `fashion_model` | optional `customPrompt` | | `photo_edit` | `user_photo` | `customPrompt` is REQUIRED (it IS the edit instruction) | | `photo_enhance` | `user_photo` | deterministic upscale, no other fields | | `remove_background` | `user_photo` | deterministic, no other fields | | `photo_reframe` | `user_photo` | needs `targetRatio` | ## GET /v1/account Email, plan status, diamond balance, and renewal date for the calling key's account: => {"success":true,"email":"brand@example.com","diamondBalance":214,"plan":{"isPremium":true,"status":"active","planProductId":"growth_yearly","provider":"revenuecat","cancelAtPeriodEnd":false,"renewsAt":"2026-09-27T00:00:00.000Z"}} `plan.status` is one of `active`, `will_expire`, `paused`, `billing_issue`, `expired`, `refunded`, `none`. ## Template sets — save a look, reuse it on new products A template set is a saved PRESET, not a new AI capability: it stores which `fashion_model`/`venue`/`pose`/`shotType`/`stylePreset`/`ratio` a past generation used, then replays that combination on a new garment. Only tools with a model/venue/pose concept can be saved: `virtual_model`, `outfit_photo`, `pro_studio`, `jewelry_on_model`, `clothing_ecom_pack`, `jewelry_ecom_pack`. ```bash # 1. Save the styling from a generation you already ran (or pass toolId + # images.fashion_model directly instead of sourceMediaId) curl -X POST https://api.fashiolabs.com/v1/template-sets \ -H "Authorization: Bearer $FASHIO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"label": "Studio white, model A, 3/4 pose", "sourceMediaId": "8b1e..."}' # => {"success":true,"id":"tset_9f2a..."} # 2. Reuse it on a NEW garment — only the new product's image is required curl -X POST https://api.fashiolabs.com/v1/generations \ -H "Authorization: Bearer $FASHIO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"templateSetId": "tset_9f2a...", "images": {"garment_photo": "https://.../new-dress.jpg"}}' # 3. Same templateSetId also works with clothing_ecom_pack / jewelry_ecom_pack # to fan one saved look out into a full catalog, not just one photo. ``` Any field the request DOES set overrides the template's saved value; `toolId` is optional when `templateSetId` is given (taken from the template) but if provided must match the template's own `toolId` (400 otherwise). - `GET /v1/template-sets` — list saved presets: `{"success":true,"templateSets":[{"id","label","toolId","images","pose","coverUrl",...}]}`. - `DELETE /v1/template-sets/{id}` — remove one. 404 if not found or not owned by this key. ## Ready template sets — Fashio's own curated photoshoot library A SEPARATE, larger catalogue from the "template sets" above — this one is curated by Fashio (not saved by the caller), each entry a full "ready photoshoot" (one model + one venue + several pinned poses/shots). Use it when you have no styling of your own to reuse yet. ```bash # 1. Browse the library curl "https://api.fashiolabs.com/v1/ready-template-sets?category=editorial&limit=10" \ -H "Authorization: Bearer $FASHIO_API_KEY" # => {"success":true,"templateSets":[{"id":"set_editorial_04","shotCount":6,"shots":[...]}],"nextCursor":...} # 2. (optional) inspect one set's full shot list curl https://api.fashiolabs.com/v1/ready-template-sets/set_editorial_04 \ -H "Authorization: Bearer $FASHIO_API_KEY" # 3. Generate one image per shot from your own product photo curl -X POST https://api.fashiolabs.com/v1/catalog-jobs \ -H "Authorization: Bearer $FASHIO_API_KEY" \ -H "Content-Type: application/json" \ -d '{"readyTemplateSetId": "set_editorial_04", "images": {"garment_photo": "https://.../dress.jpg"}}' # => {"success":true,"mediaItemId":"9c3f...","status":"pack_processing","packTotal":6,"diamondCost":18,...} # 4. Poll the SAME GET /v1/generations/{id} endpoint as every other tool. # resultUrls fills in with each completed shot; packTotal/packCompleted/ # packFailed report progress before every shot is done. curl https://api.fashiolabs.com/v1/generations/9c3f... \ -H "Authorization: Bearer $FASHIO_API_KEY" ``` Optional body fields for `POST /v1/catalog-jobs`: `shotIds` (string[], generate only these shots — omit for every shot), `ratio`, `modelId` (advanced image-to-image model override). Errors: 400 missing `readyTemplateSetId`/image, 402 insufficient diamonds for the full shot count, 404 unknown/inactive `readyTemplateSetId`. If every shot in a job fails, the whole charge is refunded automatically; partial failures are reported via `packFailed`, not refunded per-shot. ## Pricing and billing Every generation deducts diamonds (Fashio's credit unit) from the calling account's balance — the same balance shown in the app/dashboard. There is no separate API wallet. `GET /v1/models` shows a fallback price per tool; the price actually charged is resolved at request time and shown nowhere else — if in doubt, check the account's balance before and after a test call. A failed generation refunds the diamonds it charged. ## Rate limits and errors - `401` — missing, malformed, or revoked API key. - `402` — insufficient diamond balance (nothing was charged). - `404` — unknown generation id, or it belongs to a different account. - `413` / `415` — upload too large (>8MB) or not a recognized image format. - `429` — daily request cap reached for this key. - `500` — something failed after diamonds were already deducted; the generation is marked `failed` and the diamonds are refunded automatically. ## MCP (Model Context Protocol) Every endpoint above is also available as native tools for an MCP-speaking agent (Claude, Cursor, etc.), via `fashio-mcp`: - Remote, no install: add `https://mcp.fashiolabs.com/mcp` to your MCP client as a remote/HTTP server, with header `Authorization: Bearer `. - Local package: `fashio-mcp` on npm — same 14 tools (list_models, list_fashion_models, list_venues, list_poses, upload_image, create_generation, get_generation, get_account, create_template_set, list_template_sets, delete_template_set, list_ready_template_sets, get_ready_template_set, create_catalog_job), runs on your own machine via stdio. - Both variants call the exact same `api.fashiolabs.com` endpoints documented above and bill the same diamond balance — there is no separate MCP pricing or quota. - Repo: https://github.com/fashiolabs/fashio-mcp — npm: https://www.npmjs.com/package/fashio-mcp ## Official SDKs and CLI Besides raw HTTP and MCP, Fashio publishes two official clients — both thin wrappers over the exact same REST API documented above, no separate pricing: - `fashio-client` — Node.js/TypeScript SDK, one typed method per endpoint (`listModels`, `createGeneration`, `getGeneration`, `getAccount`, `createTemplateSet`, `listReadyTemplateSets`, `createCatalogJob`, ...). `npm install fashio-client`. Repo: https://github.com/fashiolabs/fashio-client — npm: https://www.npmjs.com/package/fashio-client - `fashio-cli` — command-line client for scripts and CI, built on `fashio-client`. One subcommand per endpoint, prints JSON to stdout (`fashio generate '{...}'`, `fashio status `, `fashio account`, `fashio catalog '{...}'`). `npm install -g fashio-cli` or `npx fashio-cli`. Repo: https://github.com/fashiolabs/fashio-cli — npm: https://www.npmjs.com/package/fashio-cli ## Per-tool documentation pages Every `toolId` above has its own human-facing page — request table, a runnable example in cURL/Node.js/Python, and the exact response shape — at `https://docs.fashiolabs.com/tools/.html`, e.g. `https://docs.fashiolabs.com/tools/virtual_model.html`, `https://docs.fashiolabs.com/tools/photo_reframe.html`. Getting-started guides live at `/index.html` (Introduction), `/authentication.html`, `/quickstart.html`, `/pricing.html`, `/rate-limits.html`, `/account.html`, `/template-sets.html`, `/ready-template-sets.html`, `/core-endpoints.html`; support content at `/faq.html`, `/troubleshooting.html`, `/support.html`, `/changelog.html`, `/roadmap.html`. ## Also see - OpenAPI 3.1 spec (machine-readable, same content): https://docs.fashiolabs.com/openapi.yaml - Human-facing docs home (Introduction): https://docs.fashiolabs.com/ - Interactive API reference (Redoc, same OpenAPI spec): https://docs.fashiolabs.com/api-reference.html - Browser playground (try it with your own key): https://docs.fashiolabs.com/playground.html - Fashio MCP marketing page: https://fashiolabs.com/mcp