Products
Product CRUD with variants, offers and addons, category tree operations, and per-product analytics.
Products are store-scoped catalog documents. Variants, offers and addons are embedded on the product — there are no separate variant/offer resources to manage. Reads are public (the storefront consumes them directly); writes require a bearer token with product access on the store. List conventions (pagination, flat filters, the filterator) are covered in API conventions.
At a glance
Products
| Method | Path | Description | Auth |
|---|---|---|---|
GET | /v1/products | List — store_id (or store_ids[]), q, status, category_id, price_min/price_max, in_stock, order_by=field:dir, filterator | Public |
GET | /v1/products/random | Random published products (limit, default 12) | Public |
GET | /v1/products/{id} | Show — by selects the lookup column (e.g. by=slug); merchants get a live row incl. integrationsData | Public |
POST | /v1/products | Create (multipart supported for image files) | Bearer + scope products |
PUT | /v1/products/{id} | Update | Bearer + scope products |
DELETE | /v1/products/{id} | Soft delete — members still resolve deleted products on historical orders | Bearer + scope products |
Per-product analytics
| Method | Path | Description | Auth |
|---|---|---|---|
GET | /v1/stores/{storeId}/products/{productId}/sells | Sales chart for the last 7 days (date → count) | Bearer + scope orders.read |
GET | /v1/stores/{storeId}/products/{productId}/report | Detailed report — sales/revenue/profit for today, yesterday (hourly), week, month (daily) | Bearer + scope orders.read |
GET | /v1/stores/{storeId}/products/{productId}/analytics/lor | Lite orders report (8 UTC day buckets + total) | Bearer |
Categories
Categories form a tree per store (parentId links). List endpoints take flat params only
(store_id, parent_id, q) — the filterator is not supported here.
| Method | Path | Description | Auth |
|---|---|---|---|
GET | /v1/categories | Flat list for a store — store_id, optional parent_id (null for roots), q | Public |
GET | /v1/categories/tree | Full nested tree for a store — store_id | Public |
GET | /v1/categories/{id} | Show one category | Public |
POST | /v1/categories | Create — { name, storeId, parentId?, photoUrl?, ... } | Bearer + scope categories |
PUT | /v1/categories/{id} | Update (move a subtree by changing parentId) | Bearer + scope categories |
DELETE | /v1/categories/{id} | Delete | Bearer + scope categories |
Feedbacks
Feedbacks are platform feedback (bug reports and feature requests from merchants about Feeef itself), scoped to the submitting user — they are not product reviews. Storefront product reviews are not a dedicated API resource today.
| Method | Path | Description | Auth |
|---|---|---|---|
GET | /v1/feedbacks | List own feedback (admins see all; supports filterator, status, priority, q, date filters) | Bearer |
GET | /v1/feedbacks/{id} | Show one | Bearer |
POST | /v1/feedbacks | Create — { title, details?, priority?, tags?, appVersion? }; multipart files become attachments | Bearer |
PUT | /v1/feedbacks/{id} | Update (admins may change status with history) | Bearer |
DELETE | /v1/feedbacks/{id} | Delete | Bearer |
POST | /v1/feedbacks/{id}/comments | Add a comment — { comment } | Bearer |
Variants, offers, addons
Three embedded structures drive pricing (all optional):
variant— a single root group ({ name, options[], view?, required? }). Each option can overrideprice,discount,stock,sku, and can nest another group viachild, producing a tree (e.g. Color → Size). Order items address a leaf with a slash-joinedvariantPathsuch asred/xl.offers[]— quantity bundles:{ code, title, price?, minQuantity?, maxQuantity?, freeShipping? }. Order items reference them byofferCode.forceOffer: trueon the product requires customers to keep an offer selected;defaultOfferCodepre-selects (and withforceOfferlocks) one.addons[]— optional extras purchasable alongside the product; order items carry them as a name → quantity map.
The server recalculates all prices from these structures during order calculate/submit — client-sent prices are never trusted.
List products for a storefront grid
curl "https://api.feeef.org/v1/products?store_id=STORE_ID&in_stock=1&price_max=5000&order_by=sold:desc&limit=12" \
-H "Accept: application/json"For arbitrary conditions pass a filterator — see
API conventions.
Create a product with variants and offers
curl -X POST "https://api.feeef.org/v1/products" \
-H "Authorization: Bearer $FEEEF_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"storeId": "STORE_ID",
"name": "Classic Tee",
"slug": "classic-tee",
"price": 2200,
"media": ["https://storage.feeef.net/.../tee.webp"],
"variant": {
"name": "Color",
"options": [
{ "name": "Red", "type": "color", "value": "#f00",
"child": { "name": "Size", "options": [
{ "name": "M" }, { "name": "L", "price": 2400 }
] } }
]
},
"offers": [
{ "code": "x2", "title": "Buy 2", "price": 2000, "minQuantity": 2, "freeShipping": true }
]
}'Upload images first via POST /v1/services/storage/upload (see
API conventions) and reference the returned URLs in media —
media is a plain array of URL strings.
Fetch a product by slug
curl "https://api.feeef.org/v1/products/classic-tee?by=slug"Guest reads may be served from a short-lived cache; authenticated store members always get a
live row (including the secret integrationsData — guests only ever see
publicIntegrationsData).
Category tree
curl "https://api.feeef.org/v1/categories/tree?store_id=STORE_ID"/tree returns root nodes with recursive children arrays — one request instead of one per
level. Product counts are not included; filter products by category_id instead.
Notes
- Webhooks: product create / update / delete fire
productCreated,productUpdatedandproductDeleted— same envelope as orders, with the entity underdata.product. See Webhooks. Inbound connector writes are skipped to avoid echo loops. - Slugs are unique per store; both products and stores support
?by=sluglookups. - Status: products carry a
status(e.g.published/draft) — unpublished products stay out of public lists but remain fetchable by id for their store members. - Views/sold counters update server-side (
showtracks views; orders updatesold). - Promo codes (
/v1/promos) are subscription discount codes, not product coupons — see Payments. Product-level discounts live on the product/variant/offerdiscountfields. - Related lists for landing pages and templates: see Templates.