REST API
Items API
Manage inventory items, stock levels, and valuation.
Generated from the Celerp 2.4.0 OpenAPI schema, 16 September 2026.
GET /items
List Items
List items with optional filters.
status: exact status to show (e.g. "sold", "archived", "available").
Pass "all" to skip status filtering entirely.
Default (None): exclude sold + archived from results.
category: exact category to filter on.
filter: semantic filter. "low_stock" keeps only items at or below their
reorder point (see celerp.services.reorder.is_below_reorder).
on_memo_to: customer contact_id. Scope to items currently out on memo to that
customer, valued (holding_value) at the price they were quoted.
consigned_from: supplier contact_id. Scope to items currently held on
consignment from that supplier, valued (holding_value) at cost.
When a contact scope is active the response also carries value_total,
the sum of holding_value over the whole scoped set (pre-pagination).
Parameters
| Name | In | Required | Type | Description |
|---|
limit | query | -- | integer | -- |
offset | query | -- | integer | -- |
q | query | -- | string, optional | -- |
sku | query | -- | string, optional | -- |
skus | query | -- | string, optional | -- |
barcode | query | -- | string, optional | -- |
gtin | query | -- | string, optional | -- |
rfid_epc | query | -- | string, optional | -- |
status | query | -- | string, optional | -- |
category | query | -- | string, optional | -- |
inventory_type | query | -- | string, optional | -- |
location_id | query | -- | string, optional | -- |
source | query | -- | string, optional | -- |
filter | query | -- | string, optional | -- |
on_memo_to | query | -- | string, optional | -- |
consigned_from | query | -- | string, optional | -- |
sort | query | -- | string, optional | -- |
dir | query | -- | string | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items \
-H "Authorization: Bearer $TOKEN"
POST /items
Post Item
Request body
| Field | Type | Required | Description |
|---|
sku | string, optional | -- | Sku |
name | string | yes | Name |
sell_by | string | yes | Sell By |
quantity | number | -- | Quantity |
category | string, optional | -- | Category |
location_id | string, optional | -- | Location Id |
cost_price | number, optional | -- | Cost Price |
cost_total | number, optional | -- | Cost Total |
wholesale_price | number, optional | -- | Wholesale Price |
retail_price | number, optional | -- | Retail Price |
description | string, optional | -- | Description |
unit | string, optional | -- | Unit |
barcode | string, optional | -- | Barcode |
auto_barcode | boolean | -- | Auto Barcode |
gtin | string, optional | -- | Gtin |
rfid_epc | string, optional | -- | Rfid Epc |
hs_code | string, optional | -- | Hs Code |
tax_codes | array of string | -- | Tax Codes |
purchase_sku | string, optional | -- | Purchase Sku |
purchase_name | string, optional | -- | Purchase Name |
purchase_unit | string, optional | -- | Purchase Unit |
purchase_conversion_factor | number, optional | -- | Purchase Conversion Factor |
allow_splitting | boolean | -- | Allow Splitting |
attributes | object | -- | Attributes |
idempotency_key | string, optional | -- | Idempotency Key |
inventory_type | string | -- | Inventory Type |
landed_cost_kind | string, optional | -- | Landed Cost Kind |
recoverable | boolean, optional | -- | Recoverable |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/delete
Bulk Delete
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/delete \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/expire
Bulk Expire
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/expire \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/make-available
Bulk Make Available
Commit one or more drafts into stock. Same authority as authoring the draft (edit_inventory) - no extra permission.
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/make-available \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/revert-to-draft
Bulk Revert To Draft
assert_status_change_allowed does the real gating (revert_items_to_draft + clean history).
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
reason | string, optional | -- | Reason |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/revert-to-draft \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/shopify-sync
Bulk Shopify Sync
Opt the selected items into (or out of) outbound Shopify sync by emitting
shop.sync.enabled/disabled, which sets is_sync_to_shopify on each item's projection.
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
enable | boolean | -- | Enable |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/shopify-sync \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/status
Bulk Set Status
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
status | string | yes | Status |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/status \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/bulk/transfer
Bulk Transfer
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
to_location_id | string | yes | To Location Id |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/bulk/transfer \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
GET /items/categories
List Item Categories
Return distinct non-empty category values: union of category_schemas keys and item projections.
Responses
| Status | Description | Body |
|---|
200 | Successful Response | array of string |
Example
curl -X GET http://localhost:8000/items/categories \
-H "Authorization: Bearer $TOKEN"
GET /items/export/csv
Export Items Csv
Parameters
| Name | In | Required | Type | Description |
|---|
q | query | -- | string, optional | -- |
category | query | -- | string, optional | -- |
status | query | -- | string, optional | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | -- |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/export/csv \
-H "Authorization: Bearer $TOKEN"
GET /items/field-values
Get Field Values
Return sorted distinct non-empty values for a categorical item field.
Allowed fields:
- Fields in _SUGGESTION_FIELDS (core categorical fields)
- Any attribute field (any field stored under item.attributes) - these are
module-defined and can include gemstone fields, restaurant fields, etc.
Blocked fields: FK references, free-text blobs, internal identifiers.
Returns {"values": [...]} so the caller can safely extend without breakage.
Parameters
| Name | In | Required | Type | Description |
|---|
field | query | yes | string | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/field-values \
-H "Authorization: Bearer $TOKEN"
POST /items/import/batch
Batch Import Items
Batch-import CIF item records. Idempotent on idempotency_key. Max 500 per call.
The raw-event-batch transport: records arrive already shaped by the caller.
The committer lives in services.commit_import_batch, shared with /import/rows
and the agent /import/commit.
Request body
| Field | Type | Required | Description |
|---|
records | array of ImportRecord | yes | Records |
filename | string, optional | -- | Filename |
upsert | boolean | -- | Upsert |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | celerp_inventory__services__BatchImportResult |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/import/batch \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
GET /items/import/batches
List Import Batches
List all import batches for this company, newest first.
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
Example
curl -X GET http://localhost:8000/items/import/batches \
-H "Authorization: Bearer $TOKEN"
POST /items/import/batches/{batch_id}/undo
Undo Import Batch
Undo an import batch only when none of its created items changed later.
Parameters
| Name | In | Required | Type | Description |
|---|
batch_id | path | yes | string | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/import/batches/:batch_id/undo \
-H "Authorization: Bearer $TOKEN"
POST /items/import/commit
Import Commit
Commit an item import previewed via /import/preview.
Recomputes the preview from the stored bytes; a hash mismatch means the file
or its mapping changed since the preview, refused with 409 rather than
imported under stale assumptions. Any row validation error is refused with
422 and the error list; otherwise the rows go through the shared committer.
Request body
| Field | Type | Required | Description |
|---|
file_id | string | yes | File Id |
sheet | string, optional | -- | Sheet |
upsert | boolean | -- | Upsert |
mapping | object, optional | -- | Mapping |
preview_hash | string | yes | Preview Hash |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | celerp_inventory__services__BatchImportResult |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/import/commit \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
GET /items/import/preview
Import Preview
Preview an uploaded item import for the browser UI.
Parameters
| Name | In | Required | Type | Description |
|---|
file_id | query | yes | string | -- |
sheet | query | -- | string, optional | -- |
upsert | query | -- | boolean | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | InventoryImportPreview |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/import/preview \
-H "Authorization: Bearer $TOKEN"
POST /items/import/preview
Import Preview Agent
Preview an uploaded catalog with an optional caller-corrected mapping.
Request body
| Field | Type | Required | Description |
|---|
file_id | string | yes | File Id |
sheet | string, optional | -- | Sheet |
upsert | boolean | -- | Upsert |
mapping | object, optional | -- | Mapping |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | InventoryImportPreview |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/import/preview \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/import/rows
Import Rows
Commit already-mapped import rows (the browser importer's transport).
Rows arrive mapped and fixed by the UI. The shared committer owns location
resolution and creation, unit and quantity derivation, monetary conversion,
idempotency, and the category-schema follow-up. Unmarked: this is the browser
transport, not an agent capability (the agent commits through /import/commit).
Request body
| Field | Type | Required | Description |
|---|
rows | array of object | yes | Rows |
upsert | boolean | -- | Upsert |
filename | string, optional | -- | Filename |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | celerp_inventory__services__BatchImportResult |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/import/rows \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/merge
Merge Items
Request body
| Field | Type | Required | Description |
|---|
source_entity_ids | array of string | yes | Source Entity Ids |
target_sku_from | string | yes | Target Sku From |
resulting_quantity | number, optional | -- | Resulting Quantity |
resulting_cost_total | number, optional | -- | Resulting Cost Total |
resulting_name | string, optional | -- | Resulting Name |
resulting_sku | string, optional | -- | Resulting Sku |
resolved_attributes | object, optional | -- | Resolved Attributes |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/merge \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/metadata
Items Metadata
Bulk item-metadata read: one entry per requested id, keyed by entity_id.
Returns the same visibility-filtered flat dict GET /items/{entity_id} returns
per item, minus the sold_price enrichment (list/doc/audit renderers never read
it). This is a read gated by the router-level authentication; company_id is
derived server-side from the JWT, never from the body, and the query is scoped
to that company so it cannot read another company's items. Field/cost
visibility is applied per the item's OWN category, exactly as the per-item
route does, so restricted fields never leak. Unknown ids are simply absent from
the result (no error, no fabricated entry).
Request body
| Field | Type | Required | Description |
|---|
entity_ids | array of string | yes | Entity Ids |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/metadata \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
GET /items/valuation
Get Valuation
Aggregate inventory valuation from projections.
Optional ?category= and ?status= filters scope totals + count_by_status to that slice.
on_memo_to: customer contact_id. Scope counts to items currently out on memo to that customer.
consigned_from: supplier contact_id. Scope counts to items currently held on consignment.
category_counts is always global (all active items) - used by the category tab bar.
count_by_status is scoped to the current category/status/holdings filter - used by status cards.
Parameters
| Name | In | Required | Type | Description |
|---|
category | query | -- | string, optional | -- |
status | query | -- | string, optional | -- |
on_memo_to | query | -- | string, optional | -- |
consigned_from | query | -- | string, optional | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/valuation \
-H "Authorization: Bearer $TOKEN"
GET /items/{entity_id}
Get Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/:entity_id \
-H "Authorization: Bearer $TOKEN"
PATCH /items/{entity_id}
Patch Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
fields_changed | object | -- | Fields Changed |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X PATCH http://localhost:8000/items/:entity_id \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/{entity_id}/adjust
Adjust Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
new_qty | number | yes | New Qty |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/adjust \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/{entity_id}/expire
Expire Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/expire \
-H "Authorization: Bearer $TOKEN"
POST /items/{entity_id}/price
Set Item Price
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
price_type | string | yes | Price Type |
new_price | number | yes | New Price |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/price \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
GET /items/{entity_id}/reorder-suggestion
Get Reorder Suggestion
Suggested reorder_point / reorder_qty from trailing outbound velocity.
Read-only assist for the item detail / bulk dialog - the stored fields stay the
single source of truth. Returns nulls when there is no outbound history (never
a fabricated number). See celerp.services.reorder.suggest_reorder.
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/:entity_id/reorder-suggestion \
-H "Authorization: Bearer $TOKEN"
POST /items/{entity_id}/reserve
Reserve Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
quantity | number | yes | Quantity |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/reserve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/{entity_id}/split
Split Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
children | array of SplitChild | yes | Children |
mother_qty | number, optional | -- | Mother Qty |
mother_weight | number, optional | -- | Mother Weight |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/split \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
GET /items/{entity_id}/split-preview
Split Preview
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
child_sku | query | -- | string, optional | -- |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X GET http://localhost:8000/items/:entity_id/split-preview \
-H "Authorization: Bearer $TOKEN"
POST /items/{entity_id}/status
Set Item Status
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
new_status | string | yes | New Status |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/status \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/{entity_id}/transfer
Transfer Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
to_location_id | string | yes | To Location Id |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/transfer \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/{entity_id}/transform
Transform Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
child_sku | string | yes | Child Sku |
child_category | string | yes | Child Category |
child_sell_by | string | yes | Child Sell By |
child_quantity | number | yes | Child Quantity |
child_name | string, optional | -- | Child Name |
child_weight | number, optional | -- | Child Weight |
child_weight_unit | string, optional | -- | Child Weight Unit |
child_pieces | integer, optional | -- | Child Pieces |
child_cost_total | number, optional | -- | Child Cost Total |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/transform \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'
POST /items/{entity_id}/unreserve
Unreserve Item
Parameters
| Name | In | Required | Type | Description |
|---|
entity_id | path | yes | string | -- |
Request body
| Field | Type | Required | Description |
|---|
quantity | number | yes | Quantity |
idempotency_key | string, optional | -- | Idempotency Key |
Responses
| Status | Description | Body |
|---|
200 | Successful Response | object |
422 | Validation Error | HTTPValidationError |
Example
curl -X POST http://localhost:8000/items/:entity_id/unreserve \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{ ... }'