# Adjust a product's stock level by a relative quantity, with a reason

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

The same rule logic as the admin stock adjustment: direction comes from the reason, and the write is floored at zero.

- Exactly one of `product_id` or `sku` is required. `sku` matches `product.sku` case-insensitively among live products only, and never a barcode (`product_code`).
- `Idempotency-Key` is REQUIRED: a relative delta replayed without one would double-count.

- `400 VALIDATION_FAILED`: neither or both of `product_id`/`sku` were given.
- `404 NOT_FOUND`: the `sku` does not match a live product.
- `422 INSUFFICIENT_STOCK`: the adjustment would take stock below zero.
- `422 REASON_NOT_ALLOWED`: the reason is a system reason or is turned off. A reason must be enabled and must not be a system reason.
- `422 OUTLET_DELETED`: the outlet has been deleted.

`unit_cost` (integer cents, optional) is the cost of the units added; it is blended into the outlet's average cost. Leave it out to keep the current average. It is ignored when stock does not go up.

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

Required scope: `inventory:write`

## Parameters

None.

## Request body

```
{
  note?: string | null
  occurred_on?: string | null
  outlet_id: string
  product_id?: string
  quantity: number
  reason_id: string
  sku?: string
  unit_cost?: integer | null
}
```

## Response (201)

```
{
  data: {
  adjustment_id: string
  movement_id: string
  on_hand: number
}
}
```

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/adjustments" \
  -H "Authorization: Bearer olet_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"outlet_id":"00000000-0000-0000-0000-000000000000","reason_id":"00000000-0000-0000-0000-000000000000","quantity":0}'
```
