> ## Documentation Index
> Fetch the complete documentation index at: https://docs.filexpress.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Products

> Create, retrieve, update, and delete products

**Required permission:** `products`

> [!NOTE]
>
> These endpoints use the legacy response format `{ success, data, message }`.

## List a branch's products

```http theme={null}
GET /products/branch/{branch_id}
```

Returns the active products with their unit of measure, category, and portions.

## Get a product

```http theme={null}
GET /products/{id}
```

Includes `portions` and `components` when the product has a composition.

## Create a product

```http theme={null}
POST /products
```

```json theme={null}
{
  "name": "Refresco 350ml",
  "sku": "BEB-001",
  "price_before_taxes": 1.11,
  "cost": 0.70,
  "tax_method": "is_taxed",
  "composition_type": "simple",
  "product_type": "phisical",
  "product_category_id": "uuid",
  "product_measurement_id": "uuid",
  "branch_id": "uuid",
  "availability": 100,
  "limit_availability": 10,
  "tax_ids": ["uuid-del-iva"]
}
```

| Field | Required | Description |
| - | - | - |
| `name` | Yes | Product name. |
| `price_before_taxes` | Yes | Selling price before taxes. |
| `product_category_id` | Yes | Category. See `GET /product-categories`. |
| `product_measurement_id` | Yes | Unit of measure. See `GET /product-measurements`. |
| `product_type` | Yes | `phisical` (goods), `service` (service), or `both`. |
| `tax_method` | Yes | `is_taxed` (taxable), `is_exent` (exempt), or `is_not_subject` (not subject to tax). |
| `composition_type` | Yes | `simple`, `with_portions`, or `with_recipe`. |
| `branch_id` | Yes | Branch. |
| `availability` | Yes | Initial stock. |
| `limit_availability` | Yes | Minimum stock (reorder alert). |
| `sku` | No | Internal code. |
| `cost` | No | Unit cost. |
| `tax_ids` | No | IDs of the product's taxes. Get the valid ones with [`GET /taxes/branch/{branch_id}`](#product-taxes). |

When you create goods with `availability` greater than 0, an inventory entry is recorded automatically.

## Product taxes

Taxes are assigned with `tax_ids`. These are the taxes FileXpress uses to calculate taxes when the product is sold from the web, the POS, or the app.

> [!WARNING]
>
> `tax_method: "is_taxed"` only marks the product as taxable; it **does not assign any taxes**. Always send `tax_ids` with at least VAT (IVA) on taxable products. Without it, VAT is not calculated when the product is sold from the web or the POS.

**1. Get the branch's taxes**

```http theme={null}
GET /taxes/branch/{branch_id}
```

Returns the taxes of the branch's country. `is_default: true` marks the main tax (VAT in El Salvador).

**2. Send their IDs in tax\_ids when you create or update the product**

```json theme={null}
{
  "status": true,
  "data": [
    { "id": "uuid", "name": "IVA", "number_code": "20", "tax_type": "percentage", "percent": 0.13, "value": 0, "is_default": true, "document_types": null, "country_code": "SV" },
    { "id": "uuid", "name": "FOVIAL", "number_code": "D1", "tax_type": "fixed_unit", "percent": 0, "value": 0.20, "is_default": false, "document_types": null, "country_code": "SV" }
  ]
}
```

| Field | Description |
| - | - |
| `tax_type` | `percentage` (percentage of the taxable base, in `percent`) or `fixed_unit` (fixed amount per unit, in `value`). |
| `number_code` | Tax code according to the Ministry of Finance (Hacienda). |
| `document_types` | Document types the tax applies to (`null` = all). |

**Rules**

* Only taxes from the country of the product's branch are accepted; an invalid ID returns a validation error.
* On creation, if you don't send `tax_ids`, the product has no taxes.
* On update, if you don't send `tax_ids`, the current taxes are kept; if you send `[]`, all of them are removed.
* Product responses include `taxes` with the assigned taxes.

### Product with portions

With `composition_type: "with_portions"`, `base_unit_quantity` and `base_unit` are required:

```json theme={null}
{
  "base_unit_quantity": 1000,
  "base_unit": "ml",
  "portions": [
    { "portion_name": "Vaso 250ml", "portion_quantity": 250, "portion_unit": "ml", "portion_price": 0.44, "is_active": true }
  ]
}
```

### Product with a recipe

With `composition_type: "with_recipe"`:

```json theme={null}
{
  "components": [
    { "component_product_id": "uuid-ingrediente", "quantity_needed": 2, "unit_type": "base" }
  ]
}
```

## Update a product

```http theme={null}
PUT /products/{id}
```

Accepts the same fields as creation, including `tax_ids`. If `availability` changes, an inventory adjustment is recorded. If `composition_type` changes, the previous portions or components are replaced.

## Delete a product

```http theme={null}
DELETE /products/{id}
```

Soft delete: the product no longer appears in listings.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.