Inventory API
Setting absolute stock levels — and the race this deliberately doesn't solve.
PATCH /platform/v1/products/:id/inventory — scope write_products
(inventory is a sub-resource of the product aggregate, not a separate
scope — a finer write_inventory split is possible later if a partner
needs stock-only access). Requires Idempotency-Key.
const { data } = await client.setInventory(productId, { stock: 12 }, crypto.randomUUID());
// or, for a variant:
await client.setInventory(productId, { stock: 12, variantId: "..." }, crypto.randomUUID());curl -X PATCH https://admin.prebit.in/api/platform/v1/products/$ID/inventory \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{ "stock": 12 }'Response: 200 { "data": { "productId": "...", "variantId": null, "stock": 12 } }.
This is an ABSOLUTE set, not a relative adjustment
{ "stock": 12 } means "stock is now 12," not "decrease by 12." If you
want to decrement, read the current value first (via
list products) and compute the new absolute value
yourself.
Known race with concurrent order checkouts
A live order checkout's relative decrement ($inc) and this endpoint's
absolute $set can interleave. Mongo serializes the two writes with no
data corruption, but whichever lands second silently wins — discarding
the other caller's intent. There is currently no compare-and-swap /
expectedStock precondition option. If you're syncing inventory from an
external system, be aware that a sale happening in the same moment as
your sync can be overwritten.
Errors
| Status | Cause |
|---|---|
| 400 | Invalid product id, or stock isn't a non-negative integer |
| 404 | Store not found, or product/variant not found — a variantId that doesn't match any variant on this product gives an honest 404, not a silent no-op |
| 409 | Idempotency-Key reused with a different body |
Full example
prebit-examples/inventory-sync reads a mock stock
feed and calls this endpoint per SKU, with an idempotency key derived from
productId + variantId + stock (so replaying the same feed doesn't
double-apply, but a changed stock value for the same product is
correctly treated as a new write).