# Send reorder points to a spreadsheet or another system

> Copy each category's reorder points into Google Sheets, Excel or your own ERP on a schedule, with a fresh key for every run.

Markdown twin of https://panlytics.net/developers/guides/send-reorder-points-elsewhere (last updated 2026-10-25). Every page of the Panlytics developer docs is listed at https://panlytics.net/developers/llms.txt, and all of them are in one file at https://panlytics.net/developers/llms-full.txt. The site guide is https://panlytics.net/llms.txt.

## The pattern

Reorder points (the level that triggers a new order) are worked out when they are read, and Panlytics keeps no history of them. To use them somewhere else, or to keep a record over time, a program reads them and writes them where you want them.

Because keys end within hours, the program is built to run, finish, and let its key end:

1. A person makes a key for the run, or a scheduled job asks the person for one.
2. The program reads the categories it needs.
3. It writes the figures to the spreadsheet or system.
4. The key ends on its own.

> [!WARNING]
> A key cannot be made by a program. For a job that runs every night without a person, this release has no way to do it; a person makes the key each time. Keep the job short, so one key covers it.

## Into a spreadsheet

The CSV export opens directly in Excel, Numbers and Google Sheets:

```bash title="curl"
curl "https://panlytics.net/api/v1/categories/40/reorder-points?format=csv" \
  -H "Authorization: Bearer $PANLYTICS_KEY" \
  -o "reorder-points-$(date +%F).csv"
```

Keeping one file per day gives you the history Panlytics does not store. In Google Sheets, **File**, then **Import**, then **Upload** brings a file in as a new sheet.

## Into another system

A program that feeds an ERP reads the JSON and sends each row on. This one reads every category of one shop and posts the products to order to an address of your own:

```python title="Python"
import os
import requests

API = "https://panlytics.net/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['PANLYTICS_KEY']}"}
ERP = os.environ["ERP_ORDERS_URL"]  # your own system


def every_row(path: str) -> list[dict]:
    """Every page of one list, read 200 rows at a time."""
    rows, cursor = [], None
    while True:
        params = {"limit": 200, **({"cursor": cursor} if cursor else {})}
        answer = requests.get(f"{API}{path}", headers=HEADERS, params=params, timeout=30)
        answer.raise_for_status()
        page = answer.json()
        rows.extend(page["data"])
        cursor = page["nextCursor"]
        if not cursor:
            return rows


for category in every_row("/shops/12/categories"):
    lines = every_row(f"/categories/{category['id']}/order-list")
    if lines:
        requests.post(ERP, json={"category": category["name"], "lines": lines}, timeout=30).raise_for_status()
```

Each row of the order list carries `ean`, `name`, `orderPcs`, `packSize`, `orderValueEur`, `stockPcs` and `reorderPoint`, among others. [GET /v1/categories/{id}/order-list](https://panlytics.net/developers/api/categories-order-list) lists every field.

## Doing it well

- **Read, then write.** Never send a key or a figure to a system the person did not choose.
- **Stay under the limit.** 120 calls a minute is plenty for a few hundred categories, but wait on a `429` as [Rate limits](https://panlytics.net/developers/security/rate-limits) shows.
- **Keep the CSV, not the key.** The file is yours to keep. The key is not, and it ends anyway.
- **Export is audited.** Each CSV export is written to the audit log under the key's maker, so the company can see where its figures went.
