Catalog item units, measurements, and categories

New: Units, measurements, and quantity-calculation fields on catalog items

Catalog items now expose the same unit and measurement-driven quantity calculation available in the Coperniq UI.

GET/POST/PATCH /catalog-items responses and request bodies gain:

FieldTypeDescription
unit (response) / unitId (request)object / integerThe unit this item is sold or measured in.
measurements (response) / measurementIds (request)arrayMeasurements (or a single sub-measurement) linked to drive this item’s quantity.
coveragenumberMeasurement units covered per item unit (e.g. a bundle covering ~33.33 SF).
wasteFactorMode / wasteFactorValuestring / numberWaste factor applied when computing quantity. Set together, or not at all.
1POST /catalog-items
2{
3 "name": "Architectural Shingle",
4 "type": "PRODUCT",
5 "category": "ROOF_COVERING",
6 "tradeGroup": "ENVELOPE",
7 "cost": 45,
8 "price": 90,
9 "unitId": 1924,
10 "measurementIds": [2727],
11 "coverage": 33.33,
12 "wasteFactorMode": "STATIC",
13 "wasteFactorValue": 10
14}

Notes

  • measurementIds is replace-all on PATCH, not a merge: omit it to leave existing links unchanged, or pass [] to clear all links. There’s no way to append a single measurement without resending the full set.
  • A linked measurement can be a plain measurement (one or more, summed — all must share a unit or be unitless) or a single sub-calculation (“sub-measurement”), never both. Linking a sub-calculation alongside anything else returns 400.

New: List and get catalog units

MethodPathDescription
GET/catalog-unitsList the units of measure available to your company
GET/catalog-units/{catalog_unit_id}Get a specific unit by ID

Use these IDs when setting unitId on a catalog item. Every company starts with a seeded default set (Each, Square Feet, Linear Feet, etc.); isCustom distinguishes those from any additional units a company has added.

New: List and get measurements

MethodPathDescription
GET/measurementsList measurements and sub-calculations available to your company
GET/measurements/{measurement_id}Get a specific measurement by ID

Filter with ?type=MEASUREMENT or ?type=SUB_CALCULATION. Use these IDs when setting measurementIds on a catalog item. A sub-calculation’s read-only formula shows what it computes from, but formulas can only be authored in the Coperniq UI.

New: List catalog categories

GET /catalog-categories returns the valid category codes for catalog items, grouped by PRODUCT/SERVICE, plus the available tradeGroup values — everything needed to populate category and tradeGroup on POST/PATCH /catalog-items.

Changed: tradeGroup is derived from category when omitted

POST /catalog-items previously stored tradeGroup: "OTHER" whenever the field was omitted, even for a product category that clearly belongs to another group. It is now derived from the category — ROOF_COVERING resolves to ENVELOPE, PV_MODULE to ENERGY, and so on. Services and category OTHER still resolve to OTHER. Pass tradeGroup explicitly to keep full control.

Changed: PATCH /catalog-items/{catalog_item_id} validates the resulting item, not just the patch

A partial update is now merged over the stored item and the result checked before the write, so a patch can no longer leave an item in a state POST would have rejected — for example setting category to a code outside the item’s stored tradeGroup, or adding an sku to an item that is already a SERVICE. These return 400 with the offending field. Inconsistencies that already existed on the stored item are left alone, so unrelated edits to older items keep working.

Converting a PRODUCT that has an sku into a SERVICE is still allowed and does not require clearing the sku first — services have no sku, so it is dropped as part of the conversion. Sending sku: null during that conversion is accepted and has the same effect; for an item already stored as a SERVICE, a legacy sku cannot be cleared or changed by this API and the request returns 400.