# distru-export

One script that pulls your packages, orders or products out of Distru and saves them as a CSV you can open in a spreadsheet or hand to an AI. From lesson 07-01 of the No Bullshit AI Course. Read-only: it only ever sends GET requests.

## Run it

```bash
# 1. See exactly what it would send. No key, no network.
python3 export.py --resource orders --dry-run

# 2. Get a key: Distru -> Settings -> Integrations -> Distru API -> Create API Key.
#    Keys expire one year after they are issued. Never paste the key into a chat window.
export DISTRU_API_TOKEN=...

# 3. First look: one page only.
python3 export.py --resource orders --max-pages 1

# 4. The real thing: everything changed since a date.
python3 export.py --resource orders --since 2026-09-01 --out orders.csv
python3 export.py --resource packages --since 2026-09-01
python3 export.py --resource products
```

Python 3.8 or newer, standard library only. Nothing to install.

## What it does

- Follows Distru's pagination contract: first request has no page parameter, then it follows the `next_page` URL from each response until it is `null`. It never guesses a page size.
- `--since` becomes an inclusive open-ended datetime range (`updated_datetime=2026-09-01T00:00:00.000000Z,`). The packages list filters on `inserted_datetime` instead; the script picks the right one.
- Flattens nested objects to dotted columns (`company.name`) and stores lists (`items`) as JSON text in one cell. Columns are whatever the API returns, so a new field shows up as a new column instead of breaking the script.
- Money and quantities arrive as strings (`"60.00"`). Keep them as text in your spreadsheet until you need arithmetic.
- On a 429 it waits for `Retry-After` and retries. Today only PDF endpoints are rate limited, so you should not see one.

## Dry-run output (what we saw)

```text
$ python3 export.py --resource orders --since 2026-09-01 --dry-run
DRY RUN: orders -> orders.csv
GET https://app.distru.com/public/v1/orders?updated_datetime=2026-09-01T00%3A00%3A00.000000Z%2C
  Authorization: Bearer <DISTRU_API_TOKEN>
  Content-Type: application/json
  Accept: application/json
  -> then follow response['next_page'] exactly as given, until it is null
No request was sent.
```

## Change it

The `RESOURCES` dict at the top is the only thing to edit to add another list endpoint (`/invoices`, `/companies`, `/inventory?groupings[]=PRODUCT`). Everything under `https://app.distru.com/public/v1/` uses the same auth, pagination and error envelope. Full docs: https://apidocs.distru.dev (or paste https://apidocs.distru.dev/llms.txt into your AI).

Facts above verified against Distru's API documentation and backend on 2026-09-17. Breaking changes are announced only on Distru's API email list; sign up if you build on this.

CC0 1.0. Copy it, change it, no attribution needed. Version 1.0.0.
