products:read. Create and update operations require products:write.
Scopes carry no hierarchy. A key holding
products:write cannot read the
catalogue - grant both if the integration needs to look a product up before
changing it.Search products
Requires theproducts:read scope.
search(optional) - part of a name or description, or a whole SKU or barcodeclubId(optional) - only products limited to that gymcategoryId(optional) - only products in that categorybrandId(optional) - only products of that brandisActive(optional) -truefor what is currently on sale,falsefor what has been retiredlimit(optional) - 1 to 100, defaults to 25offset(optional) - defaults to 0
search matches name and description as a substring, and sku and barcode
exactly. Half a barcode finds nothing, because a scan code is only useful whole.
Name matching works like
contact search:
case-insensitive and cross-script.
Unlike plans, retired products are
returned too. An integration that manages a catalogue has to be able to find
what it switched off in order to reprice it or bring it back. Filter with
isActive=true for what the till currently sells.Open a product
Requires theproducts:read scope.
Create a product
Requiresproducts:write. Only name and price are required. Send an
Idempotency-Key so a retry cannot create a duplicate.
400 rather than a silent drop, so
a misspelled costPrice tells you instead of leaving the margin unset.
clubId, categoryId, brandId, taxRateId, and revenueAccountId must
reference rows in your own organization. A 400 names the first one that does not.
Creating a product does not give it stock. Putting units on the shelf is done in
the 1Club dashboard - see Stock is not writable here.
Update a product
Requiresproducts:write. Send only the fields that should change.
null to clear a nullable field, and omit it to leave it
alone. images and features are arrays and replace the whole list, so read the
product first if you are adding to one.
A barcode or sku is only checked for collisions when you actually send it, so
re-saving a product without touching its codes never conflicts with itself.
Retire a product
SetisActive to false. The product comes off the till and keeps its sales
history.
There is no delete. Removing a product destroys its sales history, and a
product that still holds stock or sits in a package cannot be removed at all.
Retiring is what an integration should do; deleting outright stays in the
dashboard, where you can see what you are about to lose - see
Products.
How many are left to sell
Requires theproducts:read scope.
Stock is not writable here
Availability is the only view of stock on this API. Booking a delivery in, correcting a count after a stocktake, and writing off damaged stock all stay in the dashboard - see Inventory and stock. Stock held as ingredients that recipes draw down is not exposed here at all.Product categories
Categories are how products are grouped. They are small and flat, so there is no paging and no search - the list endpoint returns all of them, in display order.List categories
Requires theproducts:read scope.
GET /v1/platform/product-categories/{id} opens one category and returns the same
object.
Create or update a category
Requiresproducts:write.
sortOrder and the category goes to the end of the list, which is what you
want unless you are rebuilding the whole ordering. PATCH renames a category or
moves it in the order; products in it are unaffected.
Categories cannot be deleted through the API either. productCount tells you
whether one is still in use.