Products.Add
Create a product in The route mirrors the dashboard product-report product tab, accepts the real product form fields, scopes the row to the active owner, applies safe defaults for omitted DB-required fields, and emits realtime products.created. Product Type (type) options match the dashboard Type dropdown: product (Physical Product), subscription, service, donation. Default type=product when omitted. Main Image uses the same biz1upload/site/ storage as dashboard Create Product (multipart main_image file, or site_logo_old / main_image_old path).
Permissions
- User must be logged in with a valid bearer token.
- Returned or changed records are limited by the user permissions, team access, folder access, and account settings.
Action
- Creates a Products record or sends the requested data after validation.
Push Service
Pushes event products.created to users who should see this change.
Automation
Runs automation event products.created with the record id and submitted parameters after the action succeeds.
Special Instructions
- Product type (type) is a fixed dropdown — there is no separate ProductTypes.List API.
- Allowed type values (dashboard Type select): product = Physical Product; subscription = Subscription; service = Service; donation = Donation.
- Default when type is omitted: product.
- When type=subscription, use months, endless, and price_after like the dashboard subscription fields.
- Main category: cat_id from Categories.List (parent=0). Sub-category: sub_cat_id from Categories.List with parent=<cat_id>.
- Supplier: suppliers_id is a multi-select array like dashboard Create Product (select name="suppliers_id[]"). Stored as JSON e.g. ["267","170"]. Send array, suppliers_id[], JSON string, or a single id (wrapped to ["8"]). Default when omitted: []. Use Suppliers.List with for_product=1.
- Default warehouse: default_storage_id from Storage.List (storage.id — not storage_products.id).
- Main Image (dashboard Create Product image box): multipart/form-data field main_image as a file. Stored with the same FTP path as the dashboard: biz1upload/site/{owner}-{random}{time}.{ext}. Response main_image_url uses https://files.biz1.co.il/ (same as dashboard config file_url). Path aliases: site_logo_old, main_image_old.
- Optional second image: multipart sub_image (or path sub_image_old), same site folder.
- Existing JSON / x-www-form-urlencoded Products.Add calls without images still work unchanged.
Required Parameters
| Name | Type | Sample | Explanation |
|---|---|---|---|
product_namepost | string | Membership | Product name. |
Optional Parameters
| Name | Type | Sample | What it gives |
|---|---|---|---|
product_ennamepost | string | Membership | Product English name when stored. |
typepost | string | product | Product Type — same as dashboard Type select. Allowed values: product (Physical Product), subscription (Subscription), service (Service), donation (Donation). Default: product. |
cat_idpost | int | 17963 | Main category id from Categories.List. Defaults to 0 when omitted. Alias: category. |
sub_cat_idpost | int | 17964 | Sub-category id from Categories.List. Defaults to 0 when omitted. |
team_member_idpost | int | 47 | Assigned team member id when the table stores team_member_id. Defaults to the logged-in user when omitted. |
suppliers_idpost | array | ["8","12"] | Supplier ids array — same as dashboard suppliers_id[] multi-select. Stored as JSON ["8","12"]. Also accepts a single id "8" (saved as ["8"]), or repeated form field suppliers_id[]. From Suppliers.List (for_product=1). Default: []. |
suppliers_id[]post | array | 8 | Dashboard-style repeated form field for suppliers_id (multipart / form-urlencoded). Same as suppliers_id array. |
default_storage_idpost | int | 3 | Default warehouse id from Storage.List (storage.id). |
main_imagefile | file | product.jpg | Main product image file (dashboard Main Image). Use multipart/form-data. Stored as biz1upload/site/{owner}-{random}{time}.{ext}. Allowed: jpg, jpeg, png, gif, webp, bmp, tif, tiff. |
site_logo_oldpost | string | biz1upload/site/14-ab12cd341712345678.jpg | Dashboard alias: already-uploaded main image path (cropper writes site_logo_old). Used when not sending a new main_image file. Alias: main_image_old. |
sub_imagefile | file | product-alt.jpg | Optional secondary image file. Same biz1upload/site/ storage as dashboard. |
sub_image_oldpost | string | biz1upload/site/14-xy98ef761712345679.jpg | Already-uploaded secondary image path when not sending a new sub_image file. |
product_pricepost | number | 99.00 | Product price when the account stores product_price. |
main_pricepost | number | 99.00 | Dashboard alias for price. |
pricepost | number | 99.00 | Product price when the account stores price. |
costpost | number | 40.00 | Internal product cost when stored. |
cost_pricepost | number | 40.00 | Dashboard/native column name for internal product cost. |
descriptionpost | string | Monthly membership | Product description. |
product_skupost | string | MEM-001 | Stored product SKU field. |
skupost | string | MEM-001 | Product SKU when stored. |
product_internal_skupost | string | MEM-INT-001 | Internal product SKU when stored. |
discount_pricepost | number | 10.00 | Discount amount/price when stored. Alias: allowed_discount. |
stockpost | int | 10 | Initial stock quantity. Defaults to 0. |
min_stockpost | int | 2 | Minimum stock warning threshold. Defaults to 0. |
sold_stockpost | int | 0 | Sold stock counter when stored. Defaults to 0. |
left_stockpost | int | 10 | Remaining stock when stored. Defaults to stock on create. |
pay_coinpost | string | usd | Dashboard alias for the currency/coin field. |
coinpost | string | usd | Currency/coin field when stored. |
endlesspost | int | 0 | Subscription endless flag (used when type=subscription). |
monthspost | int | 12 | Subscription month count (used when type=subscription). |
price_afterpost | number | 79.00 | Subscription price after the first period (used when type=subscription). |
statuspost | int | 1 | Sets active/inactive status when stored. |
Authentication
Send the bearer token returned by Login in the request header.
Authorization: Bearer YOUR TOKEN
Sample Request
{
"url": "\/app\/Products.Add",
"method": "POST",
"headers": {
"Authorization": "Bearer YOUR TOKEN"
},
"body": {
"product_name": "Membership new product",
"type": "product",
"cat_id": "17963",
"suppliers_id": [
"8"
],
"price": "99.00",
"main_image": "@product.jpg"
},
"curl_multipart": "curl --location 'https:\/\/YOUR_HOST\/app\/Products.Add' \\\n--header 'Authorization: Bearer YOUR_TOKEN' \\\n--form 'product_name=Membership new product' \\\n--form 'type=product' \\\n--form 'price=99.00' \\\n--form 'main_image=@\/path\/to\/product.jpg'",
"url_user": "https:\/\/{user}.bull36.com\/app\/Products.Add",
"url_domain": "https:\/\/{domain}\/app\/Products.Add"
}Endpoint
POST /app/Products.Add
POST https://{user}.bull36.com/app/Products.Add
POST https://{domain}/app/Products.AddSample Output
{
"success": 1,
"id": "123",
"message": "Record added successfully.",
"main_image": "biz1upload\/site\/14-ab12cd341712345678.jpg",
"main_image_url": "https:\/\/files.biz1.co.il\/biz1upload\/site\/14-ab12cd341712345678.jpg",
"sub_image": "",
"sub_image_url": "",
"automation_event": "products.created",
"socket_event": "products.created"
}JavaScript Example
const token = 'YOUR TOKEN';
// Without image (unchanged)
const body = new URLSearchParams({
product_name: 'Membership new product',
type: 'product',
cat_id: '17963',
price: '99.00'
});
const res = await fetch('/app/Products.Add', { method: 'POST', headers: { Authorization: 'Bearer ' + token }, body });
console.log(await res.json());
// With Main Image (multipart — same as dashboard Create Product)
const form = new FormData();
form.append('product_name', 'Membership new product');
form.append('type', 'product');
form.append('price', '99.00');
form.append('main_image', fileInput.files[0]);
const res2 = await fetch('/app/Products.Add', {
method: 'POST',
headers: { Authorization: 'Bearer ' + token },
body: form
});
console.log(await res2.json());Error Example
{
"success": 0,
"message": "No supported fields were sent."
}