# Set or adjust stock levels for up to 100 product/outlet lines in one all-or-nothing request

POST https://api.oletapp.com/your-store/v1/inventory/batch

Each line names exactly one of `set` (absolute, same rules as `PUT /products/{id}/inventory/{outlet_id}`) or `adjust` (relative, same rules as `POST /inventory/adjustments`), and exactly one of `product_id` or `sku`.

- `sku` matches `product.sku` case-insensitively among live products only, never a barcode. Every `sku` in the batch is resolved in ONE query before the transaction; an unknown `sku` fails the whole batch.
- No duplicate `product_id`/`outlet_id` pair is allowed anywhere in the batch, including an `sku` line resolving to the same product/outlet as a `product_id` line.
- Rows are locked in a stable order and the whole batch commits or nothing does: one bad line fails the whole request and writes zero rows.
- `Idempotency-Key` is REQUIRED: a retried batch replayed without one could apply its relative `adjust` lines twice, moving stock again.

- `400 VALIDATION_FAILED`: a line named zero or both of `set`/`adjust`, zero or both of `product_id`/`sku`, or duplicated a `product_id`/`outlet_id` pair.
- `422 UNPROCESSABLE`: one or more `sku` values did not match a live product, naming `lines.N`.
- `422 INSUFFICIENT_STOCK`: an `adjust` line would take stock below zero, naming `lines.N`.
- `422 REASON_NOT_ALLOWED`: a line names a reason that is a system reason or is turned off, naming `lines.N`. A reason must be enabled and must not be a system reason.
- `422 OUTLET_DELETED`: a line names an outlet that has been deleted. Nothing is written.

A `set` or `adjust` line may carry `unit_cost` (integer cents, optional). On a `set` line it becomes the average cost for the outlet whatever the direction, including when on_hand is unchanged; left out, the current average is kept, or the supply price when there is none. On an `adjust` line it is blended into the average when stock goes up and ignored otherwise.

**Requires scope:** `inventory:write`

Required scope: `inventory:write`

## Parameters

None.

## Request body

```
{
  lines: {
  adjust?: { ... }
  outlet_id: string
  product_id?: string
  set?: { ... }
  sku?: string
}[]
}
```

## Response (200)

```
{
  data: { ... }[]
}
```

Errors follow the standard error envelope: https://getolet.com/resources/developers/errors.md

## Example

```bash
curl -X POST "https://api.oletapp.com/your-store/v1/inventory/batch" \
  -H "Authorization: Bearer olet_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"lines":[]}'
```
