> For the complete documentation index, see [llms.txt](https://support.ordereazi.com/central/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://support.ordereazi.com/central/developers/api-guides/products-and-stock-levels.md).

# Products and stock levels

Read products, prices, and stock from OrderEazi, and load products, prices, and stock from your own system, with the API.

An online shop needs the right products, prices, and stock, and your ERP or supplier system may hold the master list. The OrderEazi API lets you read products, prices, and stock levels (the quantity of a product in one location) out of OrderEazi. It also lets you load products, prices, and stock into it.

### Before you start

You'll need:

* **Permissions:** **Read** on **For Products** to read, and **Write** to create and change. To see each product's suppliers and costs, the key also needs **Read** on **For Supplier**.
* **The key's limits:** The organisation can hide categories, brands, suppliers, and products from your key, and choose the pricelist (a set of selling prices) that its prices come from. Hidden products don't appear. See [Authentication](/central/developers/authentication.md).
* **The inventory type:** Organisations on the Enterprise licence use Warehouse Management, with stock in warehouses and bins. Others use Simple Inventory Management. The stock endpoints differ, so ask which one the organisation uses.

### How to read products

| To get             | Call                                                                                                                            |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------- |
| One product        | `GET /api/product/{sku}`, with the SKU (stock keeping unit, the product code) URL-encoded.                                      |
| Every product      | `GET /api/product/list`. Add `?includePrices=true` for each product's price.                                                    |
| Every product code | `GET /api/product/list/codes`, for a quick list of `Code` and `ProductId`.                                                      |
| Products by ID     | `POST /api/product/id`, with a list of up to 1,000 product IDs.                                                                 |
| A search           | `GET /api/product/search?term=chair`, matching code, name, description, colour, and size. The term needs at least 3 characters. |

A product includes its `FinProductId`, `Code`, `Description`, `Categories`, `Brand`, size and colour, dimensions, `KeyValues`, and, with `includePrices=true`, one price from the key's pricelist.

A product you can't see, such as one hidden from your key, still returns `200`, with the warning "Product not found." Check `Warnings`, not just the status code.

The product list isn't paged, and it can be large. To keep a shop in step, read it once, then use [webhooks](/central/developers/webhooks.md) to hear about changes.

### How to read prices

`GET /api/product/{sku}/prices` returns a product's price on each pricelist the key can see, with any quantity breaks. `GET /api/client/{clientId}/prices` returns the prices on a client's own pricelist, and needs **Read** on **For Clients**.

### How to create or update products

Send a list of products with `POST /api/product/batch`. Each product is matched by its `Code`: a new code creates a product, and an existing code updates it.

```json
[
  {
    "Code": "CHAIR-01",
    "BaseItemCode": "CHAIR",
    "Name": "Office chair",
    "Description": "Office chair, black mesh",
    "ERPId": "ITEM-4471",
    "Categories": ["Furniture/Chairs"],
    "Brand": "Comfort",
    "ColourCode": "BLK",
    "ColourName": "Black",
    "IsActive": true,
    "ProductDimension": { "Length": 600, "Width": 600, "Height": 1100, "Weight": 12, "WeightUnitOfMeasure": "kg" },
    "Suppliers": [
      { "FinSupplierId": "9b1c7e2a-5d3f-4b8a-a1c2-3e4f5a6b7c8d", "ProductCode": "CF-889", "CostTiers": [ { "Quantity": 1, "Cost": 850.00 } ] }
    ]
  }
]
```

* **Required fields:** You must send `Code`, `BaseItemCode`, `Name`, and `Description`.
* **`ERPId`:** This is the product's ID in your ERP or accounting system, so you can match the two.
* **Categories:** Each is a path, such as `Furniture/Chairs`. Missing categories and brands are created.
* **Suppliers:** Each needs a cost tier with a `Quantity` of 1. Get each `FinSupplierId` from `GET /api/supplier/list`.
* **Prices aren't set here:** Set selling prices with the pricelist endpoint below.

> **Warning:** An update replaces the product's details. Fields you leave out, such as `Brand`, `ColourName`, or `IsActive`, are cleared, but `ERPId`, `ImageUrl`, and `Notes` are kept. Send every field each time.

### How to set prices

Send prices to a pricelist with `POST /api/pricelists/{pricelistId}`:

```json
[ { "FinProductId": "3f2a1b4c-8d9e-4f0a-b1c2-d3e4f5a6b7c8", "SellingPrice": 1450.00, "Qty": 1 } ]
```

Sending a price replaces the product's price on that pricelist. This endpoint doesn't set quantity breaks. Get the `FinProductId` from `GET /api/product/{sku}`, and the pricelist IDs from `GET /api/pricelists`.

### How to read stock levels

**On Warehouse Management (Enterprise):**

* **One product:** `GET /api/product/{sku}/stock` returns its stock in every warehouse and bin.
* **A warehouse:** `GET /api/warehouse/{warehouseId}/stock` returns a warehouse's stock, and `GET /api/warehouse/{warehouseId}/{location}/stock` returns one bin's.
* **Changes since a time:** `POST /api/stocklevel/modifiedAfter` returns stock levels changed since `FromDate`, in pages. See [Pagination](/central/developers/pagination.md).

Each stock level has its `StockLevelId`, `ActualQty` (on the shelf), `ReservedQty` (set aside for orders), `AvailableQty`, `IncomingQty`, and `AverageCost`.

**On Simple Inventory Management:** Read every stock level, in pages, with `GET /api/stocklevel/simple/{skip}/{take}`. To read some products only, send a list of SKUs with `POST /api/stocklevel/simple`.

### How to update stock levels

**On Warehouse Management (Enterprise):** Send changes, not totals. `PATCH /api/stocklevel/batch` adds or takes off a quantity for each stock level:

```json
[ { "StockLevelId": 10452, "ChangeQuantity": -3 } ]
```

For one stock level, use `PATCH /api/stocklevel/{stockLevelId}/{qtyChanged}`. Get the `StockLevelId` from the stock endpoints above.

**On Simple Inventory Management:** Send totals. `PATCH /api/stocklevel/simple/batch` sets each product's quantity in a location:

```json
[ { "SKU": "CHAIR-01", "WarehouseId": 3, "Location": "Main", "ActualQty": 40 } ]
```

Missing locations are created. Leave out `ReservedQty` to keep OrderEazi's own reservations.

**Supplier stock:** To record how much a supplier holds, rather than your own stock, use `POST /api/product/batch/stock`.

### How to manage images, key values, and other codes

* **Images:** `GET /api/product/{sku}/image` lists them. The `Url` is URL-encoded, so decode it before you use it. `POST /api/product/{sku}/image` replaces the main image, as a multipart upload in the `image` field.
* **Key values:** `GET`, `POST`, `PUT`, and `DELETE` on `/api/product/{sku}/keyvalue` work with a product's custom fields. Keys are stored in capitals. To set many at once, use `POST /api/product/batch/keyValues`.
* **Additional codes:** `/api/product/{sku}/additionalcode` works with a product's other codes, such as a barcode or a supplier's code. It's version 2.0 only.

### Related pages

* [Pagination](/central/developers/pagination.md): paging through stock levels
* [Reference data](/central/developers/api-guides/reference-data.md): warehouses, pricelists, brands, and categories
* [Webhooks](/central/developers/webhooks.md): hear when products and stock change
