Products API
Auto-generated from the OpenAPI spec. Run
node docs-site/scripts/fetch-openapi.jsto regenerate.
POST /api/v1/products
Create Product
Create a new product. Manager-only.
Request body
| Field | Required | Type | Description |
|---|---|---|---|
name | Yes | string | |
sku | No | string | |
price | Yes | number | |
stock_quantity | No | integer | |
is_active | No | boolean |
Responses
- 201 — Successful Response
- 422 — Validation Error
GET /api/v1/products
List Products
List all products. Manager-only.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
active_only | query | No | boolean | |
page | query | No | integer | |
page_size | query | No | integer |
Responses
- 200 — Successful Response
- 422 — Validation Error
GET /api/v1/products/{product_id}
Get Product
Get a product by ID. Manager-only.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
product_id | path | Yes | integer |
Responses
- 200 — Successful Response
- 422 — Validation Error
PUT /api/v1/products/{product_id}
Update Product
Update a product. Manager-only.
stock_quantity is intentionally absent from ProductUpdate — the only
code path allowed to move stock is POST /products/{id}/stock-adjustment.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
product_id | path | Yes | integer |
Request body
| Field | Required | Type | Description |
|---|---|---|---|
name | No | string | |
sku | No | string | |
price | No | number | |
is_active | No | boolean |
Responses
- 200 — Successful Response
- 422 — Validation Error
DELETE /api/v1/products/{product_id}
Deactivate Product
Deactivate a product (set is_active=False). Manager-only. Soft-delete — never a real row delete.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
product_id | path | Yes | integer |
Responses
- 200 — Successful Response
- 422 — Validation Error
POST /api/v1/products/{product_id}/photo
Upload Product Photo
Upload (or replace) a product's photo. Manager-only — Products has no client-facing surface at all, so unlike Client/Instructor this has no dual-role authorization resolver to port.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
product_id | path | Yes | integer |
Responses
- 200 — Successful Response
- 422 — Validation Error
POST /api/v1/products/{product_id}/stock-adjustment
Adjust Product Stock
Restock (or manually correct) a product's stock_quantity by a delta.
A single atomic UPDATE (stock_quantity += delta), safe under concurrent calls — this is why it takes a delta rather than an absolute "set to N", which would be a lost-update hazard between two concurrently-restocking managers. Rejects if the delta would drive stock below 0.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
product_id | path | Yes | integer |
Request body
| Field | Required | Type | Description |
|---|---|---|---|
delta | Yes | integer | |
reason | No | string |
Responses
- 200 — Successful Response
- 422 — Validation Error
POST /api/v1/product-sales
Create Product Sale
Record a completed in-person sale of one or more products.
sold_by_user_id is always set server-side from the resolved manager
user, never accepted from the request body. total_amount and every
line's line_total are always computed server-side from
unit_price_at_sale * quantity — never trusted from the request.
Request body
| Field | Required | Type | Description |
|---|---|---|---|
client_id | No | integer | |
items | Yes | array | |
payment_method | Yes | string | |
notes | No | string |
Responses
- 201 — Successful Response
- 422 — Validation Error
GET /api/v1/product-sales
List Product Sales
List product sales, newest first. Manager-only.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
client_id | query | No | ||
start_date | query | No | ||
end_date | query | No |
Responses
- 200 — Successful Response
- 422 — Validation Error
GET /api/v1/product-sales/{sale_id}
Get Product Sale
Get a product sale by ID, with nested line items. Manager-only.
Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
sale_id | path | Yes | integer |
Responses
- 200 — Successful Response
- 422 — Validation Error