Skip to main content
A product is something the gym sells over the counter: a bottle of water, a tube of grips, a towel. Products are grouped into product categories, which are the tabs on the till and the sections of a shop page. Read operations require 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 the products:read scope.
Query parameters:
  • search (optional) - part of a name or description, or a whole SKU or barcode
  • clubId (optional) - only products limited to that gym
  • categoryId (optional) - only products in that category
  • brandId (optional) - only products of that brand
  • isActive (optional) - true for what is currently on sale, false for what has been retired
  • limit (optional) - 1 to 100, defaults to 25
  • offset (optional) - defaults to 0
Response:
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 the products:read scope.
Returns the same object as one row of the search response.

Create a product

Requires products:write. Only name and price are required. Send an Idempotency-Key so a retry cannot create a duplicate.
Write bodies are strict: an unknown field is a 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.
A barcode or sku already used by another product, package, pass, or enrolled access card is a 409. Both are scannable: the till matches a scanned code against every barcode first and then against product SKUs, because retail imports print the SKU on the shelf label. A scanned code has to mean exactly one thing, so 1Club refuses the write rather than letting the new code shadow the old one at the till. The error names what kind of thing holds it, not which one - that record may sit behind a scope your key does not have.
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

Requires products:write. Send only the fields that should change.
Nothing is required. Send 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

Set isActive 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 the products:read scope.
Response:
This is not simply a shelf count. A product assembled from a recipe has no shelf, and its figure is the limit its scarcest ingredient imposes, floored to whole units.
available: null means the product is not stock-tracked at that gym, so the till will sell it freely. It does not mean the product has run out. Treat null as unlimited, not as zero.

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 the products:read scope.
Response:
GET /v1/platform/product-categories/{id} opens one category and returns the same object.

Create or update a category

Requires products:write.
Omit 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.

What the fields mean at the till

Read the category list before creating products in bulk. Nothing stops you from creating two categories with the same name, and a duplicate is easier to avoid than to merge afterwards.