Creates a sale. The sale status comes from the Default status for new sales setting in the system settings, and the status determines whether products and materials are deducted immediately (see Changing the Sale Status).
v1/orders/add.php
Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| num | string | Yes | Sale number without the prefix |
| products | array | products or materials | Product lines |
| materials | array | products or materials | Material lines. Accepted when the Enable ordering materials setting is on |
| customer_id | int | customer_id or customer_name | ID of an existing customer |
| customer_name | string | customer_id or customer_name | Customer name. If there is none, a customer is created from the customer_ prefixed fields |
| date_placed | string | No | Sale date. Default today |
| date_shipped | string | No | Shipping date |
| products_storage_id | int | No | Products storage location. Default from settings |
| materials_storage_id | int | No | Materials storage location. Default from settings |
| production | int | No | 1 to fulfill the sale by made-to-order production. Default 0 |
| delivery_price | float | No | Delivery cost. Default 0 |
| discount | float | No | Discount. Default 0 |
| notes | string | No | Notes |
The Default fulfillment method for new sales setting does not affect the API: without production, the sale is fulfilled from stock.
Sale lines
The sale's lines are passed as two arrays: products for products and materials for materials. At least one line in one of the arrays is required.
| Field | Type | Required | Description |
|---|---|---|---|
| id | int | id or sku | Product or material ID |
| sku | string | id or sku | SKU. A product is also matched by its alternative SKUs |
| amount | float | Yes | Quantity |
| total | float | Yes | Line total (not the price per unit) |
If an item is not found, the line is skipped and a message is appended to the sale notes, for example:
Product with SKU "P099", amount 2, total 5000 not found in Controlata, check sku.
If no line is found, the sale is not created.
Materials in sales are accepted only if Enable ordering materials is on under Settings → General. Otherwise a request with materials is rejected.
Customer
A customer is specified in one of two ways:
- customer_id: the ID of an existing customer, e.g. from v1/customers/add;
- customer_name: the customer's name. If there is no customer with that name, Controlata creates one together with the sale from the fields below.
| Field | Type | Description |
|---|---|---|
| customer_name | string | Name |
| customer_email | string | |
| customer_phone | string | Phone |
| customer_address_real | string | Delivery address |
| customer_address_legal | string | Legal address |
| customer_agreement | string | Agreement |
| customer_manager_name | string | Manager |
| customer_manager_post | string | Manager's position |
| customer_notes | string | Customer notes |
If both are passed, customer_id is used and customer_* are ignored. If a customer with that name already exists, the sale is linked to it and customer_* are not updated.
Sale number
Controlata adds a prefix from the Sale number prefix setting in the API connection. With the prefix "A-", the number "1001" you pass is saved as "A-1001" and returned as "A-1001".
Example request
{
"num": "1001",
"date_placed": "2026-10-06",
"customer_name": "John Smith",
"customer_phone": "+1 917 555-0145",
"customer_email": "john@example.com",
"customer_address_real": "5 Forest St, Apt 12, New York",
"products": [
{
"sku": "P001",
"amount": 2,
"total": 26000
},
{
"id": 816,
"amount": 1,
"total": 4500
}
],
"delivery_price": 500,
"discount": 1000,
"notes": "Order from the website"
}
Example response
{
"success": true,
"order_id": 43727,
"customer_id": 512
}
customer_id holds the sale's customer ID: the one found by customer_id or created from customer_name.
Errors
| Error | Reason |
|---|---|
| No num in input | num is missing or empty |
| Products is not an array | products is not an array (same for materials) |
| No products or materials in input | No line was passed |
| Materials in orders are disabled in company settings | Materials were passed, but the Enable ordering materials setting is off |
| Storage ID is not set | An empty storage location was passed |
| Storage ID not found | Storage location not found or deleted |
| Date is not a valid date in format YYYY-MM-DD | Invalid sale or shipping date |
| Invalid delivery_price value. Must be a number, 0 or greater | Delivery cost is not a number or below 0 |
| Invalid discount value. Must be a number, 0 or greater | Discount is not a number or below 0 |
| Line 0 of products must be an object | The line is not an object (instead of 0, the line number) |
| SKU or id not set for product 0 | The line has neither id nor sku |
| Amount not set for product with SKU "P001" | The line has no amount |
| Total not set for product with SKU "P001" | The line has no total |
| Amount must be greater than 0 for product with SKU "P001" | Quantity is not a number or not above 0 after rounding |
| Total must be a number for product with SKU "P001" | The line total is not a number |
| All products have wrong SKU or id | No line was found. If materials were passed, the text is "All products and materials have wrong SKU or id" |
| No customer_name or customer_id in input | No customer was passed |
| Customer not found | The customer_id customer was not found or is deleted |
| Customer name must not be empty | Empty customer_name |
| Customer name must be a string | customer_name is not a string |
In line error texts, product becomes material for material lines, and instead of SKU "P001" there is id 816 if the line was passed by id.