Tutorial: Export Your Portfolio to CSV
A small Python script that pulls every card in your inventory along with the current portfolio snapshot, then writes a CSV you can open in any spreadsheet.
What you'll need
- An IWMM API key — see Getting Started
- Python 3.10+ (no third-party libraries required)
Note: the site already exposes a one-click CSV export from the Inventory page. This tutorial is for building automation around the API — e.g. a nightly snapshot or a feed into your own portfolio dashboard.
1. The script
Save as export.py:
import csv, os, sys, urllib.request, urllib.parse, json
API = "https://iwantmymtg.net/api/v1"
KEY = os.environ["IWMM_API_KEY"]
def get(path, **params):
url = f"{API}{path}"
if params:
url += "?" + urllib.parse.urlencode(params)
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {KEY}"})
with urllib.request.urlopen(req) as r:
return json.load(r)
# 1. Portfolio snapshot
portfolio = get("/portfolio")["data"]
print(f"Total value: ${portfolio['totalValue']:.2f}", file=sys.stderr)
# 2. Walk inventory pages until exhausted
rows, page = [], 1
while True:
body = get("/inventory", page=page, limit=100)
rows.extend(body["data"])
meta = body["meta"]
if page * meta["limit"] >= meta["total"]:
break
page += 1
# 3. Write CSV
with open("inventory.csv", "w", newline="") as f:
w = csv.writer(f)
w.writerow(["set", "number", "name", "foil", "quantity", "price", "value"])
for it in rows:
price = (it.get("priceFoil") if it["isFoil"] else it.get("priceNormal")) or 0
w.writerow([
it.get("setCode", ""), it.get("cardNumber", ""), it.get("cardName", ""),
"yes" if it["isFoil"] else "no",
it["quantity"], f"{price:.2f}", f"{price * it['quantity']:.2f}",
])
print(f"Wrote {len(rows)} rows to inventory.csv", file=sys.stderr)
2. Run it
export IWMM_API_KEY=iwm_live_...
python3 export.py
Open inventory.csv
in your spreadsheet of choice.
3. Stay under the rate limit
A 1,000-card collection at limit=100
takes 11 requests (1 portfolio + 10 inventory pages) — well under the free tier's
100/day. Watch X-RateLimit-Remaining
if you're scheduling this every hour:
with urllib.request.urlopen(req) as r:
print("remaining:", r.headers.get("X-RateLimit-Remaining"))
Where to go next
- Add
/portfolio/history?days=30for a value-over-time series - Pipe the CSV into a Google Sheet via the Sheets API
- On the Developer tier, drop the per-page sleep and pull big collections in seconds