Export 90 days of price history to CSV
Last updated · Changelog · OpenAPI spec · Markdown
Write every recorded price of a list of products over the last 90 days to one CSV: one row per price point, with the product, retailer, date, price, currency and availability. The input file has an identifier header (barcodes, ASINs, model numbers or product URLs).
| Step | REST endpoint | MCP tool | Credits |
|---|---|---|---|
| History for up to 100 products, as CSV | GET /v1/products/offers/history?format=csv | product_price_history | 3 per product with offers, plus 90 per request (1 per day of the window) |
Cost for N products: 3 × N + 90 for every 100 products. 1,000 products cost 3,000 + 900 = 3,900 credits. A request in which no product has offers is not charged. Shorter windows cost less per request; the longest window is 366 days. See Retrieving Offers With Historical Offer Data.
bash
#!/usr/bin/env bash
# Export the last 90 days of recorded prices for a list of products to one CSV.
# Usage: SHOPSAVVY_API_KEY=... ./history-export.sh skus.csv history.csv
# skus.csv has an "identifier" column: barcodes, ASINs, model numbers or product URLs.
set -euo pipefail
. ./shopsavvy-call.sh
end=$(date -u +%Y-%m-%d)
start=$(date -u -v-90d +%Y-%m-%d 2>/dev/null || date -u -d '90 days ago' +%Y-%m-%d)
: > "$2"
tail -n +2 "$1" | tr -d '\r' | grep -v '^$' | split -l 100 - "$SS_TMP/chunk_"
for chunk in "$SS_TMP"/chunk_*; do
ids=$(paste -sd, "$chunk" | jq -sRr @uri)
api GET "/products/offers/history?ids=$ids&start=$start&end=$end&format=csv" > "$SS_TMP/part.csv"
# A 404 (no product with offers in this chunk) comes back as JSON, not CSV: skip it.
head -c 1 "$SS_TMP/part.csv" | grep -q '{' && continue
if [ -s "$2" ]; then tail -n +2 "$SS_TMP/part.csv" >> "$2"; else cat "$SS_TMP/part.csv" >> "$2"; fi
done
echo "Wrote $2 ($start to $end)"Python
"""Export the last 90 days of recorded prices for a list of products to one CSV.
Usage: SHOPSAVVY_API_KEY=... python history_export.py skus.csv history.csv
skus.csv has an "identifier" column: barcodes, ASINs, model numbers or product URLs.
"""
import csv
import sys
from datetime import date, timedelta
from shopsavvy_call import call
def main(source, destination):
with open(source, newline="") as f:
identifiers = [row["identifier"].strip() for row in csv.DictReader(f) if row["identifier"].strip()]
end = date.today()
start = end - timedelta(days=90)
header_written = False
with open(destination, "w", newline="") as out:
for first in range(0, len(identifiers), 100):
params = {"ids": ",".join(identifiers[first:first + 100]), "start": start.isoformat(),
"end": end.isoformat(), "format": "csv"}
response = call("GET", "/products/offers/history", not_found_ok=True, params=params)
if response.status_code == 404:
continue # none of these matched a product with offers: nothing charged
lines = response.text.splitlines(keepends=True)
out.writelines(lines if not header_written else lines[1:])
header_written = True
print(f"Wrote {destination} ({start} to {end})")
if __name__ == "__main__":
main(sys.argv[1], sys.argv[2])TypeScript
// Export the last 90 days of recorded prices for a list of products to one CSV.
// Usage: SHOPSAVVY_API_KEY=... npx tsx history-export.ts skus.csv history.csv
// skus.csv has an "identifier" column: barcodes, ASINs, model numbers or product URLs.
import { readFileSync, writeFileSync } from 'node:fs'
import { call } from './shopsavvy-call'
async function main(source: string, destination: string) {
const identifiers = readFileSync(source, 'utf8').split(/\r?\n/).slice(1).map((line) => line.trim()).filter(Boolean)
const end = new Date()
const start = new Date(end.getTime() - 90 * 24 * 60 * 60 * 1000)
const day = (d: Date) => d.toISOString().slice(0, 10)
let csv = ''
for (let first = 0; first < identifiers.length; first += 100) {
const ids = encodeURIComponent(identifiers.slice(first, first + 100).join(','))
const response = await call('GET', `/products/offers/history?ids=${ids}&start=${day(start)}&end=${day(end)}&format=csv`, { notFoundOk: true })
if (response.status === 404) continue // none of these matched a product with offers: nothing charged
const text = await response.text()
csv += csv === '' ? text : text.slice(text.indexOf('\n') + 1)
}
writeFileSync(destination, csv)
console.log(`Wrote ${destination} (${day(start)} to ${day(end)})`)
}
main(process.argv[2], process.argv[3])Was this page helpful?