# CompSniper examples

All requests send `Authorization: Bearer cs_YOUR_KEY`. Base URL `https://api.compsniper.com`.

## curl: eBay sold comps

```
curl -H "Authorization: Bearer cs_YOUR_KEY" \
  "https://api.compsniper.com/v1/scrape?keyword=nintendo%20switch%20oled&sold=true&ebaySite=ebay.com&count=240"
```

## curl: active listings on a local marketplace

```
curl -H "Authorization: Bearer cs_YOUR_KEY" \
  "https://api.compsniper.com/v1/scrape?keyword=dyson%20v11&sold=false&ebaySite=ebay.co.uk"
```

## curl: raw results (skip AI relevance cleanup)

```
curl -H "Authorization: Bearer cs_YOUR_KEY" \
  "https://api.compsniper.com/v1/scrape?keyword=lego%20star%20wars&relevance=false"
```

## curl: use purchased credits directly

```
curl -H "Authorization: Bearer cs_YOUR_KEY" -H "X-Credit-Source: credits" \
  "https://api.compsniper.com/v1/scrape?keyword=pokemon%20charizard%20psa%2010"
```

## JavaScript (fetch)

```js
const res = await fetch(
  "https://api.compsniper.com/v1/scrape?" +
    new URLSearchParams({ keyword: "air jordan 1 chicago", sold: "true", ebaySite: "ebay.com" }),
  { headers: { Authorization: "Bearer cs_YOUR_KEY" } }
);

if (!res.ok) {
  const err = await res.json();
  // err.code is one of: unauthorized, invalid_params, rate_limited,
  // quota_exceeded, upstream_blocked, server_busy, upstream_unavailable, server_error
  if (err.code === "rate_limited" || err.code === "server_busy") {
    const wait = Number(res.headers.get("Retry-After") || 2);
    // back off `wait` seconds, then retry a bounded number of times
  }
  throw new Error(`${res.status} ${err.code}: ${err.error}`);
}

const data = await res.json();
console.log(data.summary?.median, data.totalItems, data.items.length);
```

## Python (requests)

```python
import time, requests

def scrape(keyword, **params):
    headers = {"Authorization": "Bearer cs_YOUR_KEY"}
    params = {"keyword": keyword, "sold": "true", "ebaySite": "ebay.com", **params}
    for attempt in range(4):
        r = requests.get("https://api.compsniper.com/v1/scrape", headers=headers, params=params, timeout=60)
        if r.status_code == 200:
            return r.json()
        body = r.json()
        if body["code"] == "quota_exceeded":
            raise SystemExit("Quota exhausted. Upgrade, buy credits, or wait for reset.")
        if r.status_code in (429, 502, 503):
            time.sleep(int(r.headers.get("Retry-After", 2)) + attempt)  # bounded backoff
            continue
        raise RuntimeError(f'{r.status_code} {body["code"]}: {body["error"]}')
    raise RuntimeError("giving up after retries")

data = scrape("sony wh-1000xm5")
print(data["summary"]["median"], data["summary"]["p25"], data["summary"]["p75"])
```

## Bulk keyword search (up to 20 in one run)

```
curl -X POST -H "Authorization: Bearer cs_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"keywords":["nintendo switch oled","steam deck","rog ally"]}' \
  "https://api.compsniper.com/v1/bulk-search"
```

## Card batch (async, up to 100 cards)

```
# 1. start the job
curl -X POST -H "Authorization: Bearer cs_YOUR_KEY" -H "Content-Type: application/json" \
  -d '{"cards":["2020 Prizm Justin Herbert PSA 10","2018 Donruss Luka Doncic PSA 10"]}' \
  "https://api.compsniper.com/v1/cards/batch"
# 2. poll with the returned jobId until complete (results expire after 30 days)
curl -H "Authorization: Bearer cs_YOUR_KEY" "https://api.compsniper.com/v1/cards/batch/JOB_ID"
```

Notes: request bodies for POST endpoints follow the shapes documented at https://compsniper.com/docs. Prefer the base product name for the fullest set of comps; very narrow phrasings return fewer sold listings.
