Guides
Read and export reorder points
Read each product's reorder point, order quantity and days of stock left, page by page as JSON or in one go as CSV.
What you get
GET /v1/categories/{id}/reorder-points lists the products of a category whose reorder point (the level that triggers a new order) should change, the ones losing the most sales first. Each row carries the figures the app shows on the category's pages:
- the reorder point the report gave (
reorderPointNow) and the one Panlytics works out (newReorderPoint), and thechangebetween them; - the order quantity in whole pieces (
orderPcs), and thepackSize; - the stock on hand (
stockPcs) and the days of stock left (daysOfStockLeft, null for a product that sold nothing); - the sales class, sales and profit over the report, a one-sentence
reason, andkeptByHand, true when a person fixed the level as an exception.
The figures are worked out when you read them, from the category's newest report, its settings, its suppliers and its exceptions as they stand. Reorder points and order quantities explains what that means for a program. Every field is on the reference page, GET /v1/categories/{id}/reorder-points.
You need a key whose maker's role covers the category. Reading needs See the figures, which every role holds. GET /v1/shops/{id}/categories lists a shop's categories with their ids.
Read them as JSON
curl "https://panlytics.net/api/v1/categories/40/reorder-points?limit=200" \
-H "Authorization: Bearer $PANLYTICS_KEY"import os
import requests
URL = "https://panlytics.net/api/v1/categories/40/reorder-points"
HEADERS = {"Authorization": f"Bearer {os.environ['PANLYTICS_KEY']}"}
rows, cursor = [], None
while True:
params = {"limit": 200, **({"cursor": cursor} if cursor else {})}
answer = requests.get(URL, headers=HEADERS, params=params, timeout=30)
answer.raise_for_status()
page = answer.json()
rows.extend(page["data"])
cursor = page.get("nextCursor")
if not cursor:
break
print(len(rows), "products")const url = "https://panlytics.net/api/v1/categories/40/reorder-points";
const rows: unknown[] = [];
let cursor: string | null = null;
do {
const query = new URLSearchParams({ limit: "200", ...(cursor ? { cursor } : {}) });
const page = await fetch(`${url}?${query}`, {
headers: { Authorization: `Bearer ${process.env.PANLYTICS_KEY}` },
}).then((r) => r.json());
rows.push(...page.data);
cursor = page.nextCursor ?? null;
} while (cursor);
console.log(rows.length, "products");Lists come a page at a time: { data, nextCursor, total }, at most 200 rows per page and 50 when you leave limit out. Pass the nextCursor of one page as cursor to read the next, until it is null. total is how many rows the whole list has. See Pages.
Export them as CSV
Add format=csv to get the whole list in one file, ready for a spreadsheet, with the columns of the app's own download. Paging is ignored then:
curl "https://panlytics.net/api/v1/categories/40/reorder-points?format=csv" \
-H "Authorization: Bearer $PANLYTICS_KEY" \
-o soft-drinks-reorder-points.csvExporting needs Take the figures out as a spreadsheet on the maker's role in that category, the same as the download button in the app, and it is written to the audit log as an export. A shared demo account cannot export.
Only what to order now
Two narrower lists come from the same report:
| Endpoint | What it lists |
|---|---|
GET /v1/categories/{id}/order-list | Every product at or under its reorder point, best sellers first, with orderPcs and orderValueEur. The same list as Order now in the app. |
GET /v1/categories/{id}/stop-stocking | The products worth no longer stocking, most money tied up first. A product a person marked Never stop stocking is not on it. |
Both page the same way and both take format=csv too.
When it is refused
| Code | Status | What it means |
|---|---|---|
report.none | 409 | The category has no report yet. |
not_found.said | 404 | No category with that id in the key's company. |
refused | 403 | The key's maker may not see this category, or may not export it. |
api.invalid | 400 | A query parameter is not valid, such as a limit over 200 or a cursor the API did not make. detail names it. |