Stop hand-pricing every card. Pull live market price + condition multiplier, generate the right marketplace URL, and POST your listings via the seller endpoints.
POST /api/cards/recognize) → card_id + image-quality score.GET /api/cards/{id}/prices).asking_price.GET /api/cards/{id}/marketplace-urls) to point your listing at the right product page on Cardmarket/TCGPlayer./seller/listings with title / condition / price / photo.curl -H "Authorization: Bearer $CSM_KEY" \
"https://collectorstashmarket.com/api/cards/3782/marketplace-urls?variant=normal"
import os, requests
CSM, KEY = "https://collectorstashmarket.com", os.environ["CSM_KEY"]
HDR = {"Authorization": f"Bearer {KEY}"}
COND_MULT = {"NM": 0.95, "LP": 0.80, "MP": 0.55}
def smart_list(photo_path: str, condition: str, qty: int, margin: float = 1.05):
# 1. recognise
with open(photo_path, "rb") as f:
scan = requests.post(f"{CSM}/api/cards/recognize", headers=HDR, files={"file": f}).json()
if scan.get("confidence_label") not in ("high", "medium"):
return print(f"[skip] low-confidence scan: {scan.get('confidence_label')}")
card_id = scan["candidates"][0]["card_id"]
quality = (scan.get("capture_quality") or {}).get("overall_score", 0)
if quality < 0.55:
return print(f"[skip] photo quality {quality:.2f} too low — re-shoot")
# 2. price
rows = requests.get(f"{CSM}/api/cards/{card_id}/prices", headers=HDR).json().get("prices", [])
eur = [r["market_price"] for r in rows if r.get("currency") == "EUR" and r.get("market_price")]
if not eur:
return print(f"[skip] card {card_id}: no EUR prices yet")
asking = round(min(eur) * COND_MULT.get(condition, 0.95) * margin, 2)
# 3. list
resp = requests.post(f"{CSM}/seller/listings", headers=HDR, json={
"card_id": card_id,
"condition": condition,
"quantity": qty,
"price": asking,
"currency": "EUR",
})
resp.raise_for_status()
print(f"[ok] listed {card_id} → {asking} EUR ({condition} x{qty})")
smart_list("photos/charizard_base.jpg", "NM", qty=1)
// Drop the price 5% every 7 days if a listing sits unsold
import { fetch } from "undici";
const KEY = process.env.CSM_KEY!;
const HDR = { Authorization: `Bearer ${KEY}`, "Content-Type": "application/json" };
const { items } = await fetch(
"https://collectorstashmarket.com/seller/listings?status=active&sort=oldest",
{ headers: HDR },
).then((r) => r.json()) as any;
for (const l of items) {
const ageDays = (Date.now() - Date.parse(l.listed_at)) / 86_400_000;
const discount = Math.min(0.20, 0.05 * Math.floor(ageDays / 7));
if (discount === 0) continue;
const newPrice = +(l.price * (1 - discount)).toFixed(2);
await fetch(`https://collectorstashmarket.com/seller/listings/${l.id}`, {
method: "PATCH",
headers: HDR,
body: JSON.stringify({ price: newPrice }),
});
console.log(`#${l.id} ${l.price} → ${newPrice} (-${discount*100}%)`);
}
<?php
$key = getenv("CSM_KEY");
$rows = array_map("str_getcsv", file("cardmarket_export.csv"));
$header = array_shift($rows);
foreach (array_chunk($rows, 100) as $chunk) {
$payload = array_map(fn($r) => [
"card_id" => (int)$r[0],
"condition" => $r[1],
"quantity" => (int)$r[2],
"price" => (float)$r[3],
"currency" => "EUR",
], $chunk);
$ch = curl_init("https://collectorstashmarket.com/seller/listings/bulk");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => [
"Authorization: Bearer $key",
"Content-Type: application/json",
],
CURLOPT_POST => 1,
CURLOPT_POSTFIELDS => json_encode(["listings" => $payload]),
CURLOPT_RETURNTRANSFER => 1,
]);
echo curl_exec($ch), PHP_EOL;
}
const r = await fetch(
"https://collectorstashmarket.com/api/listings/fee-preview?price=120&image_protection=true",
).then((x) => x.json());
// → { gross: 120, seller_fee: 6, payout: 114, ... }
console.log(`You'll receive €${r.payout} after fees`);