Products

8 articles Maxim By Maxim

Methods for products and stock levels

Products

Products: the things you manufacture from materials. Via the API you can create, edit and delete them, set a product's components, get a list and a product's details, and update stock at storage locations. Method paths are given relative to the base API URL; the rules common to all methods (authorization, request format, partial editing, pagination) are described in API Overview and Common Rules. Methods | Method | What it does | |---|---| | v1/products/add | Creates a product | | v1/products/edit | Updates a product | | v1/products/delete | Deletes a product | | v1/products/update_stock | Sets the stock at a storage location | | v1/products/get_list | Returns the products of a storage location | | v2/products/get_entry | Returns a product's details and its components | | v1/products/get_stocks | Returns product stock across all storage locations |

Creating a Product

Creates a product together with its components. The product appears at storage location storage_id and at any storage location that stores all products or its categories. v1/products/add.php Parameters | Field | Type | Required | Description | |---|---|---|---| | name | string | Yes | Name | | unit | string | Yes | Unit of measure, a code from Units of Measure | | storage_id | int | Yes | Storage location where the stock is created | | sku | string | No | SKU | | price | float | No | Sale price per unit. Default 0 | | batch_size | float | No | Batch size: the product quantity the components are given for. Default 1 | | stock | float | No | Initial stock at storage location storage_id. Default 0 | | minimum | float | No | Minimum stock at storage location storage_id. Default 0 | | notes | string | No | Notes | | categories | array | No | Categories: objects with id or name | | suppliers | array | No | Supplier IDs from v1/suppliers/get_list | | alternative_sku | array | No | Alternative SKUs: objects with sku and label (an optional caption) | | materials | array | No | Materials in the components | | products | array | No | Subassemblies in the components | | resources | array | No | Resources in the components | A category can be passed by name: if there is no such category, it is created. The IDs of existing categories are returned by v1/categories/get_list. The uniqueness of the main and alternative SKUs is not checked. Product components The components are defined per batch (batch_size units) and passed as the arrays materials, products (subassemblies) and resources. materials and products lines | Field | Type | Required | Description | |---|---|---|---| | id | int | Yes | Material or product ID | | amount_per_batch | float | Yes | Quantity per batch | | unit | string | Yes | Line unit. From the same group as the material or product unit: for a material in "kg", "kg" or "g" fit | | loss_percent | float | No | Loss, in percent. Default 0. Accepted only if showing loss in components is enabled in the company settings | | position | int | No | Line position in the components | position sets the order of component lines in the Controlata interface, shared by materials and products. Lines without it go last, in the order passed. Controlata renumbers positions from 0, so in Retrieving a Product they may differ from the ones you passed. resources lines Each resource line contains the resource id. Whether amount_per_batch and unit are needed depends on the resource type (see Creating a Resource): | Resource type | amount_per_batch | unit | |---|---|---| | Fixed rate | Quantity per batch, e.g. work hours | Required | | Fixed rate, price specified in the product components | A money amount per batch | Not needed | | Percentage | Not passed: taken from the resource | Not needed | | Percentage, specified in the product components | The percentage | Not needed | | Depreciation | Quantity per batch, e.g. equipment hours | Required | Example request A table: 10 per batch, each batch uses 0.5 cu m of board with 5% loss, 400 screws, 40 legs (a subassembly) and 30 hours of carpenter's work. Overhead is a percentage set in the resource itself, so its id is enough. { "name": "Dining table", "sku": "P100", "unit": "pcs", "price": 45000, "batch_size": 10, "storage_id": 3999, "stock": 5, "minimum": 2, "categories": [{ "id": 21 }], "suppliers": [{ "id": 46 }], "alternative_sku": [ { "label": "Shopify", "sku": "SH-P100" } ], "materials": [ { "id": 2051, "amount_per_batch": 0.5, "unit": "cu m", "loss_percent": 5 }, { "id": 2060, "amount_per_batch": 400, "unit": "pcs" } ], "products": [ { "id": 312, "amount_per_batch": 40, "unit": "pcs" } ], "resources": [ { "id": 57, "amount_per_batch": 30, "unit": "h" }, { "id": 58 } ] } Example response { "success": true, "product_id": 3120 } Errors | Error | Reason | |---|---| | No name in input | A required field is missing (instead of name, the field's name) | | Name must not be empty | Empty name | | Name must be a string | Name passed not as a string, e.g. as an array | | Unit not set | An empty unit of measure was passed | | Unit not found | Unknown unit of measure, or a resources-only unit | | Storage ID is not set | storage_id is 0 or empty | | Storage ID not found | Storage location not found or deleted | | Batch size must be greater than 0 | Batch size is 0 or less | | Invalid price value. Must be a number | The value is not a number, e.g. "12,5" (same for batch_size, stock and minimum) | | Category 12 not found | Category not found | | Supplier not found or access denied | Supplier not found or deleted | | Alternative_sku is not an array | alternative_sku was not passed as an array | | SKU must be from 1 to 50 characters for alternative_sku 0 | The alternative SKU is empty or longer than 50 characters (the line number, from 0, at the end) | | Label must not exceed 100 characters for alternative_sku 0 | The alternative SKU caption is longer than 100 characters | Errors in component lines In the error text, instead of 2051 there is the item ID, and instead of 0 the line number in the array (from 0). | Error | Reason | |---|---| | Materials is not an array | materials was not passed as an array (same for products and resources) | | Line 0 of materials must be an object | The line is not an object (same for products and resources) | | No id for material 0 | The material id is missing or not a number (same for product) | | Material 2051 not found | Material not found or deleted | | Product 2051 not found | Product not found or deleted | | Product cannot be a component of itself | The product was added to its own components | | Amount per batch must be greater than 0 for material 2051 | The quantity is missing, not a number, or 0 after rounding to 3 decimals (same for product and resource) | | Unit not found for material 2051. Use a unit of the same group as the material unit | The unit is missing, unknown or from another group (same for product) | | Loss percent must be from 0 to 100 for material 2051 | Loss is below 0, above 100 or not a number (same for product) | | Loss percent is disabled in company settings for material 2051 | Loss was passed, but showing loss in components is disabled in the company settings (same for product) | | Resource for line 0 not found | Resource not found or deleted | | Percent must not exceed 100 for resource 2051 | The percentage in the components is above 100 | | Unit not found for resource 2051. Use a unit of the same group as the resource unit | The resource unit is missing, unknown or from another group |

Editing a Product

Updates a product and its components. Only the fields you pass are changed, the rest stay as they were. v1/products/edit.php Parameters | Field | Type | Required | Description | |---|---|---|---| | product_id | int | Yes | Product ID | | name | string | No | Name | | sku | string | No | SKU | | unit | string | No | Unit of measure | | price | float | No | Sale price per unit | | batch_size | float | No | Batch size | | notes | string | No | Notes | | minimum | float | No | Minimum stock at storage location storage_id | | storage_id | int | With minimum | Storage location where the minimum stock is changed | | categories | array | No | Categories: objects with id or name. Replace the current ones as a whole | | suppliers | array | No | Suppliers: objects with id. Replace the current ones as a whole | | alternative_sku | array | No | Alternative SKUs: objects with sku and label. Replace the current ones as a whole | | materials | array | No | Materials in the components | | products | array | No | Subassemblies in the components | | resources | array | No | Resources in the components. Replace the current ones as a whole | Product components The components are defined per batch (batch_size units) and passed as the arrays materials, products (subassemblies) and resources. materials and products lines | Field | Type | Required | Description | |---|---|---|---| | id | int | Yes | Material or product ID | | amount_per_batch | float | Yes | Quantity per batch | | unit | string | Yes | Line unit. From the same group as the material or product unit: for a material in "kg", "kg" or "g" fit | | loss_percent | float | No | Loss, in percent. Default 0. Accepted only if showing loss in components is enabled in the company settings | | position | int | No | Line position in the components | If at least one of the materials and products arrays is passed, materials and subassemblies are replaced as a whole, and the array that is not passed is treated as empty. For example, if you pass only materials, the subassemblies are removed from the components. position sets the order of component lines in the Controlata interface, shared by materials and products. Lines without it go last, in the order passed. Controlata renumbers positions from 0, so in Retrieving a Product they may differ from the ones you passed. resources lines Each resource line contains the resource id. Whether amount_per_batch and unit are needed depends on the resource type (see Creating a Resource): | Resource type | amount_per_batch | unit | |---|---|---| | Fixed rate | Quantity per batch, e.g. work hours | Required | | Fixed rate, price specified in the product components | A money amount per batch | Not needed | | Percentage | Not passed: taken from the resource | Not needed | | Percentage, specified in the product components | The percentage | Not needed | | Depreciation | Quantity per batch, e.g. equipment hours | Required | Example request A new sale price and material components. No subassemblies are passed, so they are removed from the components; resources stay the same. { "product_id": 3120, "price": 47000, "materials": [ { "id": 2051, "amount_per_batch": 0.6, "unit": "cu m", "loss_percent": 5 }, { "id": 2060, "amount_per_batch": 400, "unit": "pcs" } ] } Change only the minimum stock: { "product_id": 3120, "minimum": 3, "storage_id": 3999 } Example response { "success": true } Errors | Error | Reason | |---|---| | No product_id in input | product_id is missing | | Product not found or access denied | Product not found or deleted | | Name must not be empty | An empty name was passed | | Name must be a string | Name passed not as a string, e.g. as an array | | Unit not set | An empty unit of measure was passed | | Unit not found | Unknown unit of measure | | Unit cannot be changed to another unit group: the product is used in components of other products | Changing the unit group of a product used in other products' components | | Batch size must be greater than 0 | Batch size is 0 or less | | No storage_id in input | minimum passed without storage_id | | Storage ID not found | Storage location not found or deleted | | Product is not stored in storage location 3999, so its minimum cannot be set there | The product is not stocked at the storage location | | Invalid price value. Must be a number | The value is not a number (same for batch_size and minimum) | | Category 12 not found | Category not found | | Supplier not found or access denied | Supplier not found or deleted | | SKU must be from 1 to 50 characters for alternative_sku 0 | The alternative SKU is empty or longer than 50 characters | | Label must not exceed 100 characters for alternative_sku 0 | The alternative SKU caption is longer than 100 characters | Errors in component lines In the error text, instead of 2051 there is the item ID, and instead of 0 the line number in the array (from 0). | Error | Reason | |---|---| | Materials is not an array | materials was not passed as an array (same for products and resources) | | Line 0 of materials must be an object | The line is not an object (same for products and resources) | | No id for material 0 | The material id is missing or not a number (same for product) | | Material 2051 not found | Material not found or deleted | | Product 2051 not found | Product not found or deleted | | Product cannot be a component of itself | The product was added to its own components | | Amount per batch must be greater than 0 for material 2051 | The quantity is missing, not a number, or 0 after rounding to 3 decimals (same for product and resource) | | Unit not found for material 2051. Use a unit of the same group as the material unit | The unit is missing, unknown or from another group (same for product) | | Loss percent must be from 0 to 100 for material 2051 | Loss is below 0, above 100 or not a number (same for product) | | Loss percent is disabled in company settings for material 2051 | Loss was passed, but showing loss in components is disabled in the company settings (same for product) | | Resource for line 0 not found | Resource not found or deleted | | Percent must not exceed 100 for resource 2051 | The percentage in the components is above 100 | | Unit not found for resource 2051. Use a unit of the same group as the resource unit | The resource unit is missing, unknown or from another group |

Deleting a Product

Deletes a product. v1/products/delete.php Parameters | Field | Type | Required | Description | |---|---|---|---| | product_id | int | Yes | Product ID | Example request { "product_id": 3120 } Example response { "success": true } Errors | Error | Reason | |---|---| | No product_id in input | product_id is missing | | Product not found or access denied | Product not found or already deleted |

Updating Product Stock

Sets a product's stock at a storage location. You pass the final stock, not the change: Controlata creates an adjustment for the difference between the current and the new stock. v1/products/update_stock.php Parameters | Field | Type | Required | Description | |---|---|---|---| | product_id | int | Yes | Product ID | | storage_id | int | Yes | Storage location ID | | stock | float | Yes | New stock | | notes | string | No | Notes for the adjustment | If stock sync with Shopify is connected in Controlata, the new stock is sent to Shopify per its settings, like any other stock change. Example request { "product_id": 3120, "storage_id": 3999, "stock": 12, "notes": "Stocktake at the storage location" } Example response { "success": true } Errors | Error | Reason | |---|---| | No stock in input | A required field is missing (instead of stock, the field's name) | | Invalid stock value. Must be a number | The stock is not a number, e.g. "" or "4,2" | | Storage ID not found | Storage location not found or deleted | | Product not found or access denied | Product not found or deleted |

Retrieving a List of Products

Returns the products stocked at a storage location (including those with zero stock), sorted by name. Archived products are included too. v1/products/get_list.php Parameters | Field | Type | Required | Description | |---|---|---|---| | storage_id | int | Yes | Storage location ID | | limit | int | No | Page size, from 1 to 1000 | | offset | int | No | How many records to skip | Without limit the whole list is returned. See Common Rules for pagination. Response An array products with the product's fields and its stock at storage location storage_id, without alternative SKUs and components: | Field | Type | Description | |---|---|---| | id | int | Product ID | | name | string | Name | | sku | string | SKU | | unit | string | Unit of measure, a code from Units of Measure | | price | float | Sale price per unit | | cost | float | Cost per unit | | batch_size | float | Batch size: the product quantity the components are given for | | notes | string | Notes | | status | int | Always 1: deleted products are not returned | | archived | int | 1 if the product is archived | | stock | float | Stock at storage location storage_id | | minimum | float | Minimum stock at storage location storage_id | | planned | float | Stock change from operations in the Planned status. null if there are none | | categories | array | The product's categories: objects with id and name | | suppliers | array | The product's suppliers: objects with id and name | The total field holds the total number of products at the storage location. Example request { "storage_id": 3999, "limit": 100, "offset": 0 } Example response { "success": true, "products": [ { "id": 3120, "name": "Dining table", "sku": "P100", "price": 45000, "cost": 13604.25, "batch_size": 10, "notes": "", "status": 1, "archived": 0, "stock": 12, "minimum": 3, "planned": null, "unit": "pcs", "categories": [ { "id": 21, "name": "Furniture" } ], "suppliers": [ { "id": 52, "name": "Furniture Factory" } ] } ], "total": 1 } Errors | Error | Reason | |---|---| | No storage_id in input | storage_id is missing | | Storage ID not found | Storage location not found or deleted | | Invalid limit value. Must be between 1 and 1000 | Invalid limit | | Offset requires limit | offset passed without limit |

Retrieving a Product

Returns a product's details, its stock at a storage location and its components. v2/products/get_entry.php Parameters | Field | Type | Required | Description | |---|---|---|---| | product_id | int | Yes | Product ID | | storage_id | int | Yes | Storage location ID | The product is returned only if it is stocked at storage location storage_id. Stock across all storage locations at once is returned by v1/products/get_stocks. Response An object product with the product's fields, its stock at storage location storage_id, its categories, suppliers, alternative SKUs and components. | Field | Type | Description | |---|---|---| | id | int | Product ID | | name | string | Name | | sku | string | SKU | | unit | string | Unit of measure, a code from Units of Measure | | price | float | Sale price per unit | | cost | float | Cost per unit | | batch_size | float | Batch size: the product quantity the components are given for | | notes | string | Notes | | archived | int | 1 if the product is archived | | stock | float | Stock at storage location storage_id | | minimum | float | Minimum stock at storage location storage_id | | planned | float | Stock change from operations in the Planned status. null if there are none | | categories | array | The product's categories: objects with id and name | | suppliers | array | The product's suppliers: objects with id and name | | alternative_sku | array | Alternative SKUs: objects with label and sku | Besides these fields, the object holds the components: | Field | Type | Description | |---|---|---| | materials | array | Materials in the components | | products | array | Subassemblies in the components | | resources | array | Resources in the components | Fields of the materials, products and resources lines: | Field | Description | |---|---| | id | Material, product or resource ID | | name | Name | | sku | SKU. Materials and subassemblies only | | type | Resource calculation type. Resources only (see Creating a Resource) | | dynamic | 1 if the price or percentage is specified in the product components. Resources only | | base | Calculation basis of a percentage resource: cost or price. Resources only | | amount_per_batch | Quantity per batch | | amount_per_unit | Quantity per product unit: amount_per_batch / batch_size | | loss_percent | Loss, in percent. Materials and subassemblies only | | unit | Unit of measure. "%" for a percentage resource | | cost_per_unit | Line cost per product unit | | cost_per_batch | Line cost per batch | | position | Line position: shared by materials and products, separate for resources | For a resource of the fixed-rate type with its price in the product components, amount_per_batch holds a money amount, not a quantity. cost_per_unit and cost_per_batch account for loss when loss_percent > 0. The component lines, categories and suppliers from the response can be sent to v1/products/edit unchanged. Example request { "product_id": 3120, "storage_id": 3999 } Example response { "success": true, "product": { "id": 3120, "name": "Dining table", "sku": "P100", "price": 45000, "cost": 13604.25, "batch_size": 10, "notes": "", "archived": 0, "stock": 12, "minimum": 3, "planned": null, "unit": "pcs", "categories": [ { "id": 21, "name": "Furniture" } ], "alternative_sku": [ { "label": "Shopify", "sku": "SH-P100" } ], "suppliers": [ { "id": 46, "name": "Furnitrade Ltd" } ], "materials": [ { "id": 2051, "name": "Oak board", "sku": "M010", "amount_per_unit": 0.05, "amount_per_batch": 0.5, "loss_percent": 5, "unit": "cu m", "cost_per_unit": 7087.5, "cost_per_batch": 70875, "position": 0 }, { "id": 2060, "name": "Wood screw 4x40", "sku": "M024", "amount_per_unit": 40, "amount_per_batch": 400, "loss_percent": 0, "unit": "pcs", "cost_per_unit": 80, "cost_per_batch": 800, "position": 1 } ], "products": [ { "id": 312, "name": "Table leg", "sku": "P012", "amount_per_unit": 4, "amount_per_batch": 40, "loss_percent": 0, "unit": "pcs", "cost_per_unit": 3400, "cost_per_batch": 34000, "position": 2 } ], "resources": [ { "id": 57, "name": "Carpenter's work", "type": "rate", "dynamic": 0, "base": null, "amount_per_unit": 3, "amount_per_batch": 30, "unit": "h", "cost_per_unit": 1800, "cost_per_batch": 18000, "position": 0 }, { "id": 58, "name": "Overhead", "type": "percent", "dynamic": 0, "base": "cost", "amount_per_unit": 10, "amount_per_batch": 10, "unit": "%", "cost_per_unit": 1236.75, "cost_per_batch": 12367.5, "position": 1 } ] } } Errors | Error | Reason | |---|---| | No product_id in input | A required field is missing (instead of product_id, the field's name) | | Storage ID not found | Storage location not found or deleted | | Product not found or access denied | Product not found, deleted or not stocked at the storage location | Version v1 The v1/products/get_entry method accepts the same parameters and returns the same product fields. Only the components are represented differently, so use v2 in new integrations. | What | v1 | v2 | |---|---|---| | Components | A single components array: materials and subassemblies together | Separate materials, products and resources arrays | | id in component lines | Prefixed: "m-123" for a material, "p-45" for a subassembly | Numeric item id | | Sending lines back to add and edit | Not possible as is, the prefixed ids get in the way | Possible as is | Besides, v1 returns internal fields that v2 omits: product.status and the status of component lines (always 1) and product.percent (computed from cost and price).

Product Stock Across Storage Locations

Returns product stock across all storage locations as a single list: one row per «product, storage location» pair where the product is stocked. v1/products/get_stocks.php Parameters | Field | Type | Required | Description | |---|---|---|---| | product_ids | array | No | Product IDs. Without them, all products are returned | | storage_ids | array | No | Only these storage locations. Without them, all storage locations | | limit | int | No | Page size, from 1 to 1000 | | offset | int | No | How many records to skip | Rows are sorted by product ID and storage location ID. Deleted products and storage locations are not included. The total field holds the total number of rows matching the filters. Example request { "product_ids": [3120, 312] } Example response { "success": true, "stocks": [ { "product_id": 312, "storage_id": 3999, "stock": 86, "minimum": 40, "planned": -40 }, { "product_id": 3120, "storage_id": 3999, "stock": 12, "minimum": 3, "planned": null }, { "product_id": 3120, "storage_id": 4005, "stock": 0, "minimum": 0, "planned": 10 } ], "total": 3 } Errors | Error | Reason | |---|---| | Product_ids is not an array | product_ids was not passed as an array | | Storage_ids is not an array | storage_ids was not passed as an array | | Storage ID not found | Storage location not found or deleted | | Invalid limit value. Must be between 1 and 1000 | Invalid limit |