Stores & drivers
Store catalog & inventory
How a store's products, prices and stock relate to Tote's shared catalog, and every way to change them โ by hand, by category, or by a full sync.
Tote keeps one shared product catalog โ names, images, barcodes, categories. A store does not create products; it links catalog products to itself and sets its own price, stock and active flag for each.
flowchart LR
catalog["Tote catalog<br/>name, image, barcode, category"]
link["Store's link<br/>price, stock, is_active"]
store["Store"]
catalog --> link --> store
Customers see a product in a store only when the link exists, is active, and the product itself is active in the catalog. Stock is only checked at checkout.
Every inventory endpoint is for the store's owner; staff get 403 or 404.
By hand#
PUT stores/{store}/products/{product}setsprice,stockand/oris_activefor one linked product.DELETE stores/{store}/products/{product}removes the link.
By category#
These take store_id and category_id in the body:
products/attach-categorylinks every catalog product in the category, at the catalog price with stock 0. If any of them is already linked, nothing is attached: the response is422with their names undererrors.products/detach-categoryremoves the category's links.products/toggle-category-statuswithis_activeswitches all of the category's linked products on or off.
A category with no products returns 404.
Full sync#
POST stores/products/sync updates many products at once from the store's own system โ this is what the sync agent calls.
{
"store_id": 7,
"products": [
{ "barcode": "6281007012345", "price": 4.5, "stock": 120 },
{ "barcode": "6281007099999", "price": "abc", "stock": 3 }
]
}
- The barcode is the only identity. Any
idsent is ignored. A product is matched to the catalog by its exact barcode. - A matched product that is not linked yet is linked and active. One that is already linked gets its price and stock refreshed and keeps its
is_active, so a product the merchant switched off stays off. - A missing
priceuses the catalog price; a missingstockmeans 0. - Products left out of a sync are untouched. A sync never unlinks or zeroes anything; to stop selling something, send it with
stock: 0or switch it off. - Up to 100,000 products per request.
Every line is accounted for in the response:
{
"store_id": 7,
"summary": { "total": 2, "successful": 1, "failed": 1, "ignored": 0 },
"successful_syncs": [{ "id": 88, "barcode": "6281007012345", "price": 4.5, "stock": 120 }],
"failed_syncs": [{ "barcode": "6281007099999", "product_id": 91, "reason": "invalid_price" }],
"ignored": []
}
| Outcome | reason |
Meaning |
|---|---|---|
| ignored | missing_identity |
No barcode |
| ignored | product_not_found |
The barcode is not in Tote's catalog. Tote adds catalog products; the store cannot |
| failed | invalid_price |
price is not a number |
| failed | invalid_stock |
stock is not a whole number |
| failed | db_error |
The write failed; every pending line is reported failed. Retry the sync |
Statistics#
GET stores/{store}/statistics returns the store's dashboard figures for the merchant app's home screen.