Developers › Docs › API reference › Create a product
Create a product
Creates one product from photos, plus whatever details you already have. AI fills in anything you leave out (title, description, brand, category, condition, size, colours and, if you don't send one, price) from the photos, exactly as the FLUF app does. The product isn't listed anywhere yet. Publish it with POST /items.
curl -X POST "https://fluf.io/wp-json/fc/api/v1/products" \
-H "Authorization: Bearer fluf_pat_your_token" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: my-product-8812" \
-d '{
"photos": ["https://example.com/img/8812-front.jpg", "https://example.com/img/8812-back.jpg"],
"title": "Vintage Levi'"'"'s 501 jeans",
"price": 42.00,
"sku": "LV-501-32",
"size": "W32 L32"
}'const res = await fetch("https://fluf.io/wp-json/fc/api/v1/products", {
method: "POST",
headers: {
"Authorization": "Bearer fluf_pat_your_token",
"Content-Type": "application/json",
"Idempotency-Key": "my-product-8812",
},
body: JSON.stringify({
"photos": [
"https://example.com/img/8812-front.jpg",
"https://example.com/img/8812-back.jpg"
],
"title": "Vintage Levi's 501 jeans",
"price": 42.0,
"sku": "LV-501-32",
"size": "W32 L32"
}),
});
const data = await res.json();import requests
res = requests.post(
"https://fluf.io/wp-json/fc/api/v1/products",
headers={
"Authorization": "Bearer fluf_pat_your_token",
"Idempotency-Key": "my-product-8812",
},
json={
"photos": [
"https://example.com/img/8812-front.jpg",
"https://example.com/img/8812-back.jpg",
],
"title": "Vintage Levi's 501 jeans",
"price": 42.0,
"sku": "LV-501-32",
"size": "W32 L32",
},
)
data = res.json()<?php
// composer require guzzlehttp/guzzle
$client = new GuzzleHttp\Client();
$res = $client->request('POST', 'https://fluf.io/wp-json/fc/api/v1/products', [
'headers' => [
'Authorization' => 'Bearer fluf_pat_your_token',
'Idempotency-Key' => 'my-product-8812',
],
'json' => [
'photos' => [
'https://example.com/img/8812-front.jpg',
'https://example.com/img/8812-back.jpg',
],
'title' => 'Vintage Levi\'s 501 jeans',
'price' => 42.0,
'sku' => 'LV-501-32',
'size' => 'W32 L32',
],
]);
$data = json_decode((string) $res->getBody(), true);{
"vid": "fluf_326428506_0",
"fluf_id": 326428506,
"product": {
"title": "Vintage Levi's 501 jeans",
"description": "Classic straight-leg 501s in a mid-blue wash…",
"price": 42,
"currency": "GBP",
"sku": "LV-501-32",
"stock": 1,
"brand": "Levi's",
"category": "Jeans",
"condition": "Used - Good",
"size": "W32 L32",
"department": "Men",
"colours": ["Blue"],
"photos": ["https://fluf.io/wp-content/uploads/…/fc_external_….jpg"]
},
"ai_filled": ["description", "brand", "category", "condition", "department", "colours"]
}Body parameters
| Field | Type | Notes |
|---|---|---|
photos | array | Required. 1–20 public http(s) image URLs, in display order. Or upload files as multipart photos[] |
title | string | Max 255 characters |
description | string | Plain text |
price | number | Major units. If sent, AI never changes it |
brand, category, condition, size, department | string | Free text. FLUF maps them to each marketplace's own values when you publish |
colours | array | e.g. ["Blue"] |
sku | string | Your stock code |
stock | integer | Default 1 |
cost | number | What you paid. Used by pricing rules, never shown to buyers |
weight | number | Package weight, in your store's unit |
ai | boolean | Default true. With false, nothing is generated and title and price are required |
Returns
201 with the created product. ai_filled names the fields the AI supplied, so you can review them before publishing.
Retrying safely
Send an Idempotency-Key header with a value unique to the product on your side. If a request times out and you retry with the same key within 24 hours, you get the first response back (200) instead of a second product.
Errors
A photo FLUF can't download fails the whole request with 422 (photo_unreachable or photo_not_an_image) and names the photo. Nothing is created from a partial set of photos.
| HTTP | Code | Meaning |
|---|---|---|
400 | missing_photos | No photos sent |
400 | too_many_photos | More than 20 |
400 | bad_field | A field has the wrong type, e.g. a negative price |
400 | missing_fields | "ai": false without title and price |
422 | photo_unreachable, photo_not_an_image, bad_photo_url | One photo couldn't be used. photo names it |
502 | ai_failed | AI couldn't read the photos. Send the fields yourself, or retry |
Something missing? Email [email protected] — we prioritise by what people actually ask for.
