Cliento API reference: Colour bar
Base URL: https://api.cliento.com
The Colour bar APIs are for hair salons. They let an integration manage a salon's stock of hair colour and keep it correct as the colour is used.
Hair colour is not sold to the customer. It is used a little at a time: a tube is opened, and each mix takes some grams from it. The colour bar keeps track of both the packs in stock and how much is left in the open one.
There are three APIs:
- Colour bar ranges. A range is a supplier's series, such as one brand's permanent colours.
- Colour bar items. An item is one shade in a range. Each item has its own stock.
- Colour bar mixes. A mix is what a staff member mixed for one customer. Registering a mix takes the grams used from each item's stock.
Deliveries are recorded through the Stock movements API.
Colour bar ranges
Industry: hair and beauty. The Colour bar ranges API lets an integration read a salon's ranges and create, change and delete them.
A range is a supplier's series, such as one brand's permanent colours. It has an id of the form
cbr_... and belongs to a location. The items of a range share three settings, which are set on
the range: kind, packSize and listPrice.
Ranges are under /v1/locations/{locationId}/colour-bar-ranges. A range is also read by its id,
without its location, at /v1/colour-bar-ranges/{colourBarRangeId}. Reading needs the scope
products:read. Writing needs stock:write.
kindis a lower-case word such ascolour,bleachordeveloper. The list is open: send the word that fits.- A range without a
packSizeis one whose items are used a whole pack at a time, such as a treatment. Its items have no open pack, except an item with apackSizeof its own. listPriceis the supplier's list price of one pack, VAT excluded. It is what the location values its use of the range's items at, and is not what the location paid.- An item can have a
packSizeand alistPriceof its own. Changing the range'spackSizeorlistPricechanges what applies to every item without a value of its own. - A range that still has items cannot be deleted. Delete its items first.
List colour bar ranges
GET /v1/locations/{locationId}/colour-bar-ranges
Scope: products:read
Stability: preview
The location's colour bar ranges by name, one page at a time.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
limit | query | integer (int32) | No | Page size, 1 to 200. Default 50. |
after | query | string | No | The nextCursor of the previous page. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarRangeList |
| default | Any failure. See the Errors section. | Error |
Create a colour bar range
POST /v1/locations/{locationId}/colour-bar-ranges
Scope: stock:write
Stability: preview
Adds a range to the location's colour bar. It holds no items until they are created. Send an Idempotency-Key so that a repeat of the call does not add the range twice.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarRangeCreate
Responses
| Status | Description | Body |
|---|---|---|
| 201 | Created | ColourBarRange |
| default | Any failure. See the Errors section. | Error |
Get a colour bar range
GET /v1/locations/{locationId}/colour-bar-ranges/{colourBarRangeId}
Scope: products:read
Stability: preview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarRangeId | path | string | Yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarRange |
| default | Any failure. See the Errors section. | Error |
Get a colour bar range by id
GET /v1/colour-bar-ranges/{colourBarRangeId}
Scope: products:read
Stability: preview
The same colour bar range as under its location, found from its id. For a caller that holds an id and not the location it belongs to. The answer carries locationId.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
colourBarRangeId | path | string | Yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarRange |
| default | Any failure. See the Errors section. | Error |
Update a colour bar range
PATCH /v1/locations/{locationId}/colour-bar-ranges/{colourBarRangeId}
Scope: stock:write
Stability: preview
Changes only the fields in the request. Either all of them are changed or none. See ColourBarRangeUpdate for how to clear a field.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarRangeId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarRangeUpdate
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarRange |
| default | Any failure. See the Errors section. | Error |
Delete a colour bar range
DELETE /v1/locations/{locationId}/colour-bar-ranges/{colourBarRangeId}
Scope: stock:write
Stability: preview
Deleting a range that still has items is refused with not_allowed. Delete its items first.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarRangeId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Responses
| Status | Description | Body |
|---|---|---|
| 204 | No Content | |
| default | Any failure. See the Errors section. | Error |
Colour bar items
Industry: hair and beauty. The Colour bar items API lets an integration read a salon's colour bar items and create, change and delete them.
An item is one shade in a range. It can also be one strength of a developer or one tub of bleach.
It has an id of the form cbi_... and belongs to its range's location.
Each item has its own stock. The stock is counted in packs. The item also keeps how many grams have been taken from the open pack.
An item is not a product. A product is sold at a point of sale and is read through the Products API. An item is used in the salon and is never sold.
Items are under /v1/locations/{locationId}/colour-bar-items. An item is also read by its id,
without its location, at /v1/colour-bar-items/{colourBarItemId}. Reading needs the scope
products:read. Writing needs stock:write.
- Stock is counted in packs, and the open pack counts as one.
packsis4for three unopened tubes and one that is open.openUsedis the grams that have been taken from the open pack, and0when none is open. unopenedPacks,openLeftandgramsLeftare worked out frompacks,openUsedand the pack size, and are read-only.packsandopenUsedare read-only here. A delivery adds packs and a withdrawal takes them: record both through the Stock movements API, on a line with the item'scolourBarItemIdand the quantity in whole packs.openUsedchanges when a colour bar mix is registered, in Cliento or through the Colour bar mixes API.- An item follows its range's
packSizeandlistPriceunless it has its own. The item's own values arepackSizeandlistPrice;packSizeInUseandlistPriceInUseare what applies. eansholds the item's barcodes. An item made from an article in a supplier's catalogue also has that article's barcodes, whichcatalogueEanslists. Only the item's own barcodes are added and removed here.- To find the item for a scanned barcode or a row of a delivery note, list with
eanorarticleNumber. Look up the barcode first: a supplier can change its article numbers, and a barcode stays with the pack. - A range holds a shade once: a second item with the same
shadeis refused withduplicate. - An item without a
nameof its own is called by itsshade.
List colour bar items
GET /v1/locations/{locationId}/colour-bar-items
Scope: products:read
Stability: preview
The location's colour bar items, range by range and shade by shade, one page at a time. With ean or articleNumber it is a lookup: the item a scanned barcode or a delivery note row belongs to, at most 20 items. Send one of rangeId, ean and articleNumber, or none.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
limit | query | integer (int32) | No | Page size, 1 to 200. Default 50. |
after | query | string | No | The nextCursor of the previous page. |
rangeId | query | string | No | Only the items of this colour bar range. |
ean | query | string | No | Only items with this barcode: their own, or that of the supplier's article they were made from. |
articleNumber | query | string | No | Only items with exactly this article number. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarItemList |
| default | Any failure. See the Errors section. | Error |
Create a colour bar item
POST /v1/locations/{locationId}/colour-bar-items
Scope: stock:write
Stability: preview
Adds an item to a colour bar range. It starts with no stock. Send an Idempotency-Key so that a repeat of the call does not add the item twice. A shade the range already holds, or a barcode that another item or a product of the location has, is refused with duplicate.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarItemCreate
Responses
| Status | Description | Body |
|---|---|---|
| 201 | Created | ColourBarItem |
| default | Any failure. See the Errors section. | Error |
Get a colour bar item
GET /v1/locations/{locationId}/colour-bar-items/{colourBarItemId}
Scope: products:read
Stability: preview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarItemId | path | string | Yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarItem |
| default | Any failure. See the Errors section. | Error |
Get a colour bar item by id
GET /v1/colour-bar-items/{colourBarItemId}
Scope: products:read
Stability: preview
The same colour bar item as under its location, found from its id. For a caller that holds an id and not the location it belongs to. The answer carries locationId.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
colourBarItemId | path | string | Yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarItem |
| default | Any failure. See the Errors section. | Error |
Update a colour bar item
PATCH /v1/locations/{locationId}/colour-bar-items/{colourBarItemId}
Scope: stock:write
Stability: preview
Changes only the fields in the request. Either all of them are changed or none. See ColourBarItemUpdate for how to clear a field. An item stays in its range, and its stock is not changed here.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarItemId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarItemUpdate
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarItem |
| default | Any failure. See the Errors section. | Error |
Delete a colour bar item
DELETE /v1/locations/{locationId}/colour-bar-items/{colourBarItemId}
Scope: stock:write
Stability: preview
Removes the item from the colour bar with whatever stock it holds, and frees its own barcodes.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarItemId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Responses
| Status | Description | Body |
|---|---|---|
| 204 | No Content | |
| default | Any failure. See the Errors section. | Error |
Add a barcode to a colour bar item
POST /v1/locations/{locationId}/colour-bar-items/{colourBarItemId}/eans
Scope: stock:write
Stability: preview
Gives the item a barcode of its own, as when a delivery row was matched by its article number and its barcode is new. A barcode that another item or a product of the location has is refused with duplicate.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarItemId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarBarcode
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarItem |
| default | Any failure. See the Errors section. | Error |
Remove a barcode from a colour bar item
DELETE /v1/locations/{locationId}/colour-bar-items/{colourBarItemId}/eans/{ean}
Scope: stock:write
Stability: preview
Removes one of the item's own barcodes. Removing one of its catalogueEans is refused with not_allowed.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarItemId | path | string | Yes | |
ean | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarItem |
| default | Any failure. See the Errors section. | Error |
Colour bar mixes
Industry: hair and beauty. The Colour bar mixes API lets an integration register what staff mix, read it, undo it and total it per staff member. It is for an integration that weighs or doses colour itself and wants Cliento's stock and totals to follow.
A mix is what a staff member mixed for one customer. It has an id of the form cbm_... and
belongs to a location. A mix has one or more bowls. A bowl has components. A component names one
colour bar item and how many grams were taken from it.
Registering a mix takes the grams used from each item's stock. The grams are added to the item's
openUsed. When a pack is finished, the item's packs goes down by one. That change is recorded
as a stock movement of the type withdrawal.
Mixes are under /v1/locations/{locationId}/colour-bar-mixes. A mix is also read by its id,
without its location, at /v1/colour-bar-mixes/{colourBarMixId}. Reading needs the scope
products:read. Registering needs stock:write. Undoing needs stock:correct.
- Amounts are whole grams, as weighed. For an item with no pack size the amount is whole packs.
- A pack leaves the stock when it is finished. The caller says so with
openedNewPack: trueon the component for which a new pack was opened. If the finished pack ran out midway,fromFinishedPacksays how many grams of the amount still came out of it. What was never taken from the finished pack is kept on the component asresidue. - A pack also counts as finished without the caller saying so, when more has been taken from
it than it holds, unless the location has switched that off in Cliento. That setting is not
readable through the API: read
packsFinishedon each component of the answer to see what the mix took from stock. - A mix is never refused because an item is out of stock. What was mixed has been mixed; the
item's
packsstays at0. listValueis what the mix took at the supplier's list price, VAT excluded, worked out when the mix is registered and kept. A later change of a list price does not change it. A component'slistValuehas up to four decimals; the mix's is their sum rounded to two.- Give the mix your own
externalReference. Sending the same reference again changes nothing and answers200with the mix made the first time, also when that mix has been undone. A reference already used for a mix by another staff member is refused withnot_allowed. To find the mix for a reference, list withexternalReference. staffIdnames the staff member who mixed. Read it from the Staff API.personIdalso saves the mix on that person as a recipe, in the same call, and the mix then carries itsrecipeId. It needs the scopecustomers:writeas well.- A mix is not changed. A mistake is undone: every pack the mix took is put back, the grams
it added to each item's
openUsedare taken off again, and its recipe is removed. The mix is then registered again under a newexternalReference. An undone mix stays readable, withundoneAt. - The summary totals the mixes of a period per staff member at
listValue, leaving out the ones that were undone. A location uses these totals to charge the colour used to a staff member who rents a chair. - A location that keeps medical records, such as a clinic, has no colour bar mixes: every call
is refused with
not_allowed.
List colour bar mixes
GET /v1/locations/{locationId}/colour-bar-mixes
Scope: products:read
Stability: preview
The location's mixes, newest first, one page at a time, including those that were undone. With staffId, one staff member's. With externalReference, the mix registered under that reference, if there is one; it is sent without staffId and after.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
limit | query | integer (int32) | No | Page size, 1 to 200. Default 50. |
after | query | string | No | The nextCursor of the previous page. |
staffId | query | string | No | Only the mixes of this staff member. |
externalReference | query | string | No | Only the mix with this external reference. Not together with staffId or after. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarMixList |
| default | Any failure. See the Errors section. | Error |
Register a colour bar mix
POST /v1/locations/{locationId}/colour-bar-mixes
Scope: stock:write
Stability: preview
Registers what was mixed and changes the colour bar items it names. It is never refused because an item is out of stock: what was mixed has been mixed. Send an externalReference, your own id for the mix, to make the call safe to repeat: when the location already has a mix under it, that mix is returned unchanged with 200, and a reference used for another staff member's mix is refused with not_allowed. With personId the mix is also saved on that person as a recipe, which needs the scope customers:write as well. Not available at a location that keeps medical records.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarMixCreate
Responses
| Status | Description | Body |
|---|---|---|
| 200 | A mix with this externalReference already existed. | ColourBarMix |
| 201 | The mix was registered. | ColourBarMix |
| default | Any failure. See the Errors section. | Error |
Get a colour bar mix
GET /v1/locations/{locationId}/colour-bar-mixes/{colourBarMixId}
Scope: products:read
Stability: preview
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarMixId | path | string | Yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarMix |
| default | Any failure. See the Errors section. | Error |
Get a colour bar mix by id
GET /v1/colour-bar-mixes/{colourBarMixId}
Scope: products:read
Stability: preview
The same colour bar mix as under its location, found from its id. For a caller that holds an id and not the location it belongs to, such as one read from a stock movement. The answer carries locationId.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
colourBarMixId | path | string | Yes |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarMix |
| default | Any failure. See the Errors section. | Error |
Total colour bar mixes per staff member
GET /v1/locations/{locationId}/colour-bar-mixes/summary
Scope: products:read
Stability: preview
What was mixed from from to to, both days included, in the location's time zone, per staff member, at list price. Mixes that were undone are left out. The period is at most 366 days. A location uses these totals to charge the colour used to a staff member who rents a chair.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
from | query | string (date) | Yes | The first day, as YYYY-MM-DD. |
to | query | string (date) | Yes | The last day, as YYYY-MM-DD. |
staffId | query | string | No | Only this staff member. |
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarMixSummary |
| default | Any failure. See the Errors section. | Error |
Undo a colour bar mix
POST /v1/locations/{locationId}/colour-bar-mixes/{colourBarMixId}/undo
Scope: stock:correct
Stability: preview
Undoes the whole mix, once: every pack it took is put back, the grams it added to each item's openUsed are taken off again, and the recipe it was saved as is removed. The mix stays, with undoneAt. A mix that is already undone is refused with not_allowed.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
locationId | path | string | Yes | |
colourBarMixId | path | string | Yes | |
Idempotency-Key | header | string | No | A value you make up for this one request, such as a UUID. Send the same value when you retry and the first answer is returned; see Retrying safely. Example: 8e03978e-40d5-43e8-bc93-6894a57f9324. |
Request body: ColourBarMixUndo
Responses
| Status | Description | Body |
|---|---|---|
| 200 | OK | ColourBarMix |
| default | Any failure. See the Errors section. | Error |
Schemas
ColourBarBarcode
| Field | Type | Required | Description |
|---|---|---|---|
ean | string | Yes | The barcode, at most 50 characters. Example: 4064666230412. |
ColourBarItem
Represents one thing a location mixes from at its colour bar: one shade of a colour, one strength of a developer, one tub of bleach. Belongs to a colour bar range and to the range's location. Holds its own balance in the location's stock, counted in packs, and how much has been taken from the pack that is open. It is not a product: it is never sold at a point of sale.
| Field | Type | Required | Description |
|---|---|---|---|
articleNumber | string | No | The supplier's article number, as read from a delivery note. Example: 99350118254. |
catalogueEans | array of string | Yes | Read-only. Those of eans that the item has from the article in a supplier's catalogue it was made from. They are not the item's own and cannot be removed from it. Can be empty. Example: []. |
createdAt | string (date-time) | Yes | Example: 2026-10-12T08:15:30Z. |
eans | array of string | Yes | The item's barcodes: its own, and those in catalogueEans. Can be empty. Example: ["4064666230412"]. |
gramsLeft | integer (int64) | No | Read-only. Grams left in all the item's packs together. Left out when the item has no pack size. Example: 203. |
id | string | Yes | Colour bar item id. Example: cbi_3Vn8Kq5TzL1xWc7PdM2RbJ. |
listPrice | string | No | The list price of one pack, VAT excluded, where the item differs from its range. Left out when the item follows the range's listPrice. Example: 137.00. |
listPriceInUse | string | No | Read-only. The list price that applies: the item's own, otherwise its range's. Example: 137.00. |
locationId | string | Yes | Example: loc_4fK9xQ2mLr8TzB1vNc7HdW. |
name | string | Yes | What the item is called. An item without a name of its own is called by its shade, and follows it when the shade is changed. Example: 7/10. |
openLeft | integer (int32) | No | Read-only. Grams left in the open pack. Left out when no pack is open or the item has no pack size. Example: 23. |
openUsed | integer (int32) | Yes | Read-only. Grams taken from the open pack. 0 when no pack is open. Example: 37. |
packSize | integer (int32) | No | Grams in one pack, where the item differs from its range. Left out when the item follows the range's packSize. Example: 60. |
packSizeInUse | integer (int32) | No | Read-only. The pack size that applies: the item's own, otherwise its range's. Left out for an item used a whole pack at a time. Example: 60. |
packs | integer (int32) | Yes | Read-only. The packs in stock, the open one included. Never negative. Example: 4. |
rangeId | string | Yes | The range the item belongs to. Set when the item is created. Example: cbr_7Hc2Lm9QxT4vBn6KdR1WsP. |
shade | string | No | The shade of a colour, as the supplier writes it. Example: 7/10. |
strengthPercent | string | No | The strength of a developer in per cent, as a decimal string. Example: 6. |
unopenedPacks | integer (int32) | Yes | Read-only. The packs that are not opened. Example: 3. |
updatedAt | string (date-time) | Yes | When the item last changed, which includes its stock and its own barcodes. Example: 2026-10-12T08:15:30Z. |
ColourBarItemCreate
| Field | Type | Required | Description |
|---|---|---|---|
articleNumber | string | No | Example: 99350118254. |
eans | array of string | No | The item's own barcodes. A barcode that another item or a product of the location has is refused. Example: ["4064666230412"]. |
listPrice | string | No | The list price of one pack, VAT excluded, when the item differs from its range. Example: 149.00. |
name | string | No | What the item is called. Required when there is no shade. Example: Blondor Multi Blonde. |
packSize | integer (int32) | No | Grams in one pack, when the item differs from its range. Example: 60. |
rangeId | string | Yes | The range the item belongs to. Example: cbr_7Hc2Lm9QxT4vBn6KdR1WsP. |
shade | string | No | The shade of a colour, at most 50 characters. A range holds a shade once. Example: 7/10. |
strengthPercent | string | No | The strength of a developer in per cent, greater than 0, at most 100. Example: 6. |
ColourBarItemList
| Field | Type | Required | Description |
|---|---|---|---|
data | array of ColourBarItem | Yes | |
nextCursor | string | No | Pass as after to fetch the next page. Absent on the last page. Example: cbi_3Vn8Kq5TzL1xWc7PdM2RbJ. |
ColourBarItemUpdate
A JSON merge patch: send only what changes. A field you leave out keeps its value; a field set to null is cleared, but an item must keep a name or a shade. A name equal to the shade is not a name of its own: the item is called by its shade and follows it. Clearing packSize or listPrice makes the item follow its range again.
| Field | Type | Required | Description |
|---|---|---|---|
articleNumber | string | No | Example: 99350118254. |
listPrice | string | No | Example: 149.00. |
name | string | No | Example: Blondor Multi Blonde. |
packSize | integer (int32) | No | Example: 60. |
shade | string | No | Example: 7/10. |
strengthPercent | string | No | Example: 6. |
ColourBarMix
Represents what one staff member mixed at a location's colour bar at one time: one or more bowls, each with the colour bar items it took from and how much of each. Belongs to a location. Registering it changes the items it names: what was taken is added to an item's openUsed, and a pack is taken from stock when one is finished. A mix is not changed afterwards; it can be undone.
| Field | Type | Required | Description |
|---|---|---|---|
bowls | array of ColourBarMixBowl | Yes | |
createdAt | string (date-time) | Yes | Example: 2026-10-12T08:15:30Z. |
externalReference | string | No | Your own id for the mix. Example: mix-2026-10-12-0042. |
id | string | Yes | Colour bar mix id. Example: cbm_8Wq3Nd6HtY1mKx4LcP9RvB. |
listValue | string | Yes | What the mix took, at the list prices then, VAT excluded: its components' listValue together, rounded to two decimals, as a decimal string in the location's currency. Example: 91.33. |
locationId | string | Yes | Example: loc_4fK9xQ2mLr8TzB1vNc7HdW. |
note | string | No | Example: 35 min. |
recipeId | string | No | The recipe the mix was saved as on a person, when it was. Example: rcp_6Jn2Xw8QdT5bVh3ZmK7LsF. |
registeredBy | string | No | The name of who mixed: the staff member, or the API key when none was named. Example: Anna. |
staffId | string | No | The staff member who mixed. Left out when none was named. Example: stf_2Hs7Bq4MnX9cLk1VtR6PzD. |
title | string | No | Example: Roots and lengths. |
undoneAt | string (date-time) | No | When the mix was undone. Left out for a mix that stands. Example: 2026-10-12T09:02:11Z. |
undoneBy | string | No | The name of who undid the mix. Example: Anna. |
updatedAt | string (date-time) | Yes | When the mix last changed: when it was undone, otherwise createdAt. Example: 2026-10-12T08:15:30Z. |
ColourBarMixBowl
One bowl of a mix.
| Field | Type | Required | Description |
|---|---|---|---|
components | array of ColourBarMixComponent | Yes | |
ratio | string | No | Colour to developer, as it was sent. Kept as it is. Example: 1:1. |
title | string | No | Example: Roots. |
ColourBarMixBowlCreate
| Field | Type | Required | Description |
|---|---|---|---|
components | array of ColourBarMixComponentCreate | Yes | |
ratio | string | No | Colour to developer, such as 1:1 or 1:1.5. Stored as it is. Example: 1:1. |
title | string | No | Example: Roots. |
ColourBarMixComponent
What a mix took from one colour bar item, and how that left the item.
| Field | Type | Required | Description |
|---|---|---|---|
amount | integer (int32) | Yes | How much was taken: grams, or whole packs of an item that has no pack size. Example: 30. |
colourBarItemId | string | Yes | Example: cbi_3Vn8Kq5TzL1xWc7PdM2RbJ. |
fromFinishedPack | integer (int32) | No | The grams of amount that came out of the finished pack before it ran out, when a new pack was opened midway. Example: 12. |
listValue | string | No | What amount was worth at the list price then, VAT excluded, as a decimal string with up to four decimals. Left out when the item had no list price. Example: 68.5000. |
name | string | Yes | What the item was called when the mix was registered. Example: 7/10. |
openUsed | integer (int32) | Yes | The item's openUsed after this component. Example: 30. |
openedNewPack | boolean | Yes | Whether a new pack was opened for this component. Example: false. |
packs | integer (int32) | Yes | The item's packs after this component. Example: 4. |
packsFinished | integer (int32) | Yes | The packs this component finished, which is what it took from stock. Example: 0. |
residue | integer (int32) | No | Set only when openedNewPack is true: the pack size less the grams that had been taken from the finished pack. Example: 3. |
shade | string | No | The item's shade when the mix was registered. Example: 7/10. |
ColourBarMixComponentCreate
| Field | Type | Required | Description |
|---|---|---|---|
amount | integer (int32) | Yes | How much was taken, as a whole number greater than 0: grams as weighed, or whole packs of an item that has no pack size. Example: 30. |
colourBarItemId | string | Yes | Example: cbi_3Vn8Kq5TzL1xWc7PdM2RbJ. |
fromFinishedPack | integer (int32) | No | With openedNewPack: the grams of amount that still came out of the finished pack before it ran out. Leave out when the whole amount came from the new pack. Refused with validation_failed for an item that has no pack size. Example: 12. |
openedNewPack | boolean | No | true when a new pack was opened for this component: the pack that was open before is then finished and leaves the stock. Example: false. |
ColourBarMixCreate
| Field | Type | Required | Description |
|---|---|---|---|
bowls | array of ColourBarMixBowlCreate | Yes | |
externalReference | string | No | Your own id for the mix, at most 100 characters. A mix the location already has under it is returned unchanged. Example: mix-2026-10-12-0042. |
note | string | No | Example: 35 min. |
personId | string | No | A person to save the mix on as a recipe, in the same call. Needs the scope customers:write as well. Example: per_9Tk4Yc1WvN7pQe2XhB5MdG. |
staffId | string | No | The staff member who mixed. Read it from the Staff API. Example: stf_2Hs7Bq4MnX9cLk1VtR6PzD. |
title | string | No | Example: Roots and lengths. |
ColourBarMixList
| Field | Type | Required | Description |
|---|---|---|---|
data | array of ColourBarMix | Yes | |
nextCursor | string | No | Pass as after to fetch the next page. Absent on the last page. Example: cbm_8Wq3Nd6HtY1mKx4LcP9RvB. |
ColourBarMixStaffTotal
What one staff member mixed over the period, mixes that were undone left out.
| Field | Type | Required | Description |
|---|---|---|---|
listValue | string | Yes | Their listValue together, as a decimal string. Example: 3480.25. |
mixes | integer (int32) | Yes | How many mixes. Example: 42. |
name | string | No | Example: Anna. |
staffId | string | No | The staff member. Left out for mixes registered with no staff member. Example: stf_2Hs7Bq4MnX9cLk1VtR6PzD. |
ColourBarMixSummary
What was mixed at a location from one day to another, per staff member, at list price.
| Field | Type | Required | Description |
|---|---|---|---|
from | string (date) | Yes | Example: 2026-10-01. |
listValue | string | Yes | The listValue of all staff together, as a decimal string. Example: 12940.75. |
staff | array of ColourBarMixStaffTotal | Yes | One total per staff member who mixed. |
to | string (date) | Yes | Example: 2026-10-31. |
ColourBarMixUndo
| Field | Type | Required | Description |
|---|---|---|---|
staffId | string | No | The staff member who undoes the mix. Read it from the Staff API. Example: stf_2Hs7Bq4MnX9cLk1VtR6PzD. |
ColourBarRange
Represents a supplier's series as a location keeps it at its colour bar, such as one brand's permanent colours. Belongs to a location. Holds what its items have in common: their kind, the size of a pack and its list price. Colour bar items belong to it.
| Field | Type | Required | Description |
|---|---|---|---|
brand | string | No | Example: Wella. |
createdAt | string (date-time) | Yes | Example: 2026-10-12T08:15:30Z. |
id | string | Yes | Colour bar range id. Example: cbr_7Hc2Lm9QxT4vBn6KdR1WsP. |
kind | string | Yes | What the range's items are used as, such as colour or developer. A lower-case word; the list is open. Example: colour. |
listPrice | string | No | The supplier's list price of one pack, VAT excluded, as a decimal string in the location's currency. Example: 137.00. |
locationId | string | Yes | Example: loc_4fK9xQ2mLr8TzB1vNc7HdW. |
name | string | Yes | What the range is called at the location. Example: Koleston Perfect ME+. |
packSize | integer (int32) | No | Grams in one pack of the range's items. Left out for a range whose items are used a whole pack at a time. Example: 60. |
series | string | No | The supplier's name of the series. Example: KP ME+. |
updatedAt | string (date-time) | Yes | When the range itself was last changed. Example: 2026-10-12T08:15:30Z. |
ColourBarRangeCreate
| Field | Type | Required | Description |
|---|---|---|---|
brand | string | No | Example: Wella. |
kind | string | Yes | What the range's items are used as, such as colour or developer: a lower-case word of at most 30 characters. Example: colour. |
listPrice | string | No | The supplier's list price of one pack, VAT excluded. Example: 137.00. |
name | string | Yes | What the range is called at the location, at most 255 characters. Example: Koleston Perfect ME+. |
packSize | integer (int32) | No | Grams in one pack. Leave out for a range whose items are used a whole pack at a time. Example: 60. |
series | string | No | The supplier's name of the series. Example: KP ME+. |
ColourBarRangeList
| Field | Type | Required | Description |
|---|---|---|---|
data | array of ColourBarRange | Yes | |
nextCursor | string | No | Pass as after to fetch the next page. Absent on the last page. Example: cbr_7Hc2Lm9QxT4vBn6KdR1WsP. |
ColourBarRangeUpdate
A JSON merge patch: send only what changes. A field you leave out keeps its value; a field set to null is cleared. name and kind cannot be cleared.
| Field | Type | Required | Description |
|---|---|---|---|
brand | string | No | Example: Wella. |
kind | string | No | Example: colour. |
listPrice | string | No | Example: 137.00. |
name | string | No | Example: Koleston Perfect ME+. |
packSize | integer (int32) | No | Grams in one pack. Changing it changes the pack size of every item of the range that has none of its own. Example: 60. |
series | string | No | Example: KP ME+. |
Error
The body of every non-2xx response.
| Field | Type | Required | Description |
|---|---|---|---|
code | string | Yes | Stable, machine-readable error code. Values today: invalid_request, validation_failed, entity_not_found, duplicate, merchant_required, code_already_used, gift_card_already_used, pin_not_recognised, insufficient_stock, not_allowed, request_in_progress, idempotency_key_reused, unauthenticated, forbidden, account_blocked, rate_limited, route_not_found, method_not_allowed, internal_error. |
details | object of any value | No | Extra detail. For validation_failed, fieldErrors maps each rejected field to the reason. |
message | string | Yes | Human-readable explanation. Not stable; do not parse it. |