Products
The Product object — a concrete configuration of a configurator, or a standalone item — its bill of materials, de-duplication by hash, and the endpoints to list, create, update and delete products.
A product is one concrete thing that can be put on an order: a configurator with specific control values (a 1200×1600 roller blind in Blackout 605), or a standalone item. A product stores its bill of materials and cut-list, so its cost can be computed and warehouse automations know what to write off.
Products are de-duplicated. Each product has a hash of its configurator, configuration and materials; creating a
product identical to an existing one returns the existing one instead.
Field types follow the field notation.
Access
Every endpoint on this page requires both the projects and products OAuth scopes. The user must be a member of
the project, and the owner's subscription must be active. Otherwise the endpoint returns 404 RES_NOT_FOUND. The
project owner bypasses permission checks.
| Permission | Grants |
|---|---|
can_view_products |
Read products |
can_edit_products |
Create, update and delete products |
Product Object
Product Structure
| Field | Type | Description |
|---|---|---|
| uuid | uuid | Product ID |
| configurator_uuid | ?uuid | Configurator the product was built with; null for a standalone item |
| name | string | Name, 1–1024 characters |
| configuration | ?object | Control values, keyed by control id, e.g. {"$width": 1200, "$cloth": "Blackout 605"} |
| materials | array | Bill of materials, see Product Material Structure |
| parts | array | Cut-list rows, as calculated_parts of Calculate Configurator |
| unit | string | Unit of the product |
| hash | string | SHA-1 of the configurator, configuration and materials, used for de-duplication |
| orders_count | integer | Number of order lines using this product. Only in Get Product |
| created_at | ISO8601 datetime | When the product was created |
| updated_at | ISO8601 datetime | When the product was last changed |
Product Material Structure
| Field | Type | Description |
|---|---|---|
| uuid | uuid | Material ID |
| name | string | Material name |
| unit | string | Material unit |
| quantity | string/number | Quantity of the material per one product, in its unit |
This is the shape the app stores, taken from a configurator calculation. The API accepts any array, but the order cost
(purchase_price of order lines) and warehouse write-offs read only uuid and quantity. Materials that are not
linked to the product's configurator are ignored when computing cost.
Example Product
{
"uuid": "0199a3f1-5c2e-7d40-b1a2-3c4d5e6f7a8b",
"configurator_uuid": "0199ab16-3d4e-7f50-8162-738495061728",
"name": "Roller blind Blackout 605, 1200×1600 mm",
"configuration": {
"$width": 1200,
"$height": 1600,
"$cloth": "Blackout 605"
},
"materials": [
{
"uuid": "0199a2c0-7a1b-7c2d-8e3f-a0b1c2d3e4f5",
"name": "Blackout 605",
"unit": "sm",
"quantity": "2.268"
}
],
"parts": [
{
"name": "Blackout 605",
"quantity": 1,
"unit": "pcs",
"size": "1157×1600",
"size_unit": "mm"
}
],
"unit": "pcs",
"hash": "3f1c9a5e0b7d2c4e6f8a1b3d5e7f9a0c2e4b6d8f",
"orders_count": 4,
"created_at": "2026-10-01T09:20:00.000Z",
"updated_at": "2026-10-01T09:20:00.000Z"
}
List Products
GET /api/v1/projects/{project.uuid}/products
Returns a page of products, newest first, without orders_count.
Requires can_view_products.
Query String Params
| Field | Type | Description |
|---|---|---|
| page? | integer | Page number, from 1. Default 1 |
| limit? | integer | Page size, 1–100. Default 50 |
| filters? | string | A URL-encoded JSON array of {"field", "value"} objects. Invalid JSON is ignored |
Filters with the same field combine with OR; different fields combine with AND.
| field | value | Matches |
|---|---|---|
name |
string | Name contains the value, case-insensitive |
unit |
string | Exact unit |
configurator / configurator_uuid |
uuid | Products of this configurator |
Response
200 OK — {data, page, limit, total, total_pages}, as in List Materials.
Get Product
GET /api/v1/projects/{project.uuid}/products/{product.uuid}
Returns a single product with orders_count.
Requires can_view_products.
Create Product
POST /api/v1/projects/{project.uuid}/products
Creates a product, or returns the existing identical one.
Requires can_edit_products.
JSON Params
| Field | Type | Description |
|---|---|---|
| name | string | 1–1024 characters |
| configurator_uuid? | ?uuid | Configurator in this project |
| configuration? | object | Control values; each value a string, number, boolean or null |
| materials? | array | Bill of materials. Default [] |
| parts? | array | Cut-list. Default [] |
| unit? | string | Up to 16 characters; an invalid value becomes pcs. Ignored when configurator_uuid is set: the configurator's product_unit is used |
name and parts do not take part in the hash. Two requests with the same configurator, configuration and materials
but different names return the same product, with the first name.
Example Request
The usual flow is to run Calculate Configurator and save its result:
{
"name": "Roller blind Blackout 605, 1200×1600 mm",
"configurator_uuid": "0199ab16-3d4e-7f50-8162-738495061728",
"configuration": {
"$width": 1200,
"$height": 1600,
"$cloth": "Blackout 605"
},
"materials": [
{
"uuid": "0199a2c0-7a1b-7c2d-8e3f-a0b1c2d3e4f5",
"name": "Blackout 605",
"unit": "sm",
"quantity": "2.268"
}
],
"parts": []
}
Response
201 Created for a new product:
{
"uuid": "0199a3f1-5c2e-7d40-b1a2-3c4d5e6f7a8b",
"hash": "3f1c9a5e0b7d2c4e6f8a1b3d5e7f9a0c2e4b6d8f"
}
200 OK if an identical product already exists:
{
"uuid": "0199a3f1-5c2e-7d40-b1a2-3c4d5e6f7a8b",
"unit": "pcs",
"hash": "3f1c9a5e0b7d2c4e6f8a1b3d5e7f9a0c2e4b6d8f"
}
Modify Product
PATCH /api/v1/projects/{project.uuid}/products/{product.uuid}
Updates only the fields you send, with the same rules as Create Product. At least one field must be present. The hash is recomputed.
If the change makes the product identical to another existing product, the two are merged: order lines and
warehouse stock move to the other product, this product is deleted, and the response is 200 OK with:
{
"merged_into": "0199a3f1-77d0-7a11-8c9b-0a1b2c4d5e6f"
}
Otherwise the response is 204 No Content.
Requires can_edit_products.
Replace Product
PUT /api/v1/projects/{project.uuid}/products/{product.uuid}
Same as Modify Product, but every field of Create Product is required.
Delete Product
DELETE /api/v1/projects/{project.uuid}/products/{product.uuid}
Deletes the product and its stock in every warehouse. Order lines that used it keep their prices and quantities but
lose the link (product_uuid: null). Warehouse automations can then no longer write off its materials for those
orders.
Requires can_edit_products.
Response
204 No Content
Errors
| Status | Code | When |
|---|---|---|
| 400 | REQ_VALIDATION_FAILED |
The body does not match the schema |
| 400 | REQ_NO_DATA_PROVIDED |
Modify only: the body has no fields |
| 403 | AUTH_INSUFFICIENT_SCOPE |
The token lacks projects or products |
| 403 | AUTH_NO_PROJECT_ACCESS |
The user's role lacks can_view_products (read) or can_edit_products (write) |
| 404 | RES_NOT_FOUND |
The project, product, or (on create) configurator_uuid does not exist |