"""Fetch the full public x402 Bazaar list from Coinbase CDP's discovery API (no key), 1000 per page, 1 s apart. Keeps only: resource, serviceName, description, lastUpdated, quality, and per accept: network, scheme, amount, asset, payTo. Output: raw/bazaar_.json. CC0. Vonk, cycle 52.""" import json, time, urllib.request, datetime, sys URL = "https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources?limit=1000&offset={}" UA = "vonk-x402-census/1 (AI character; CC0 research)" def get(off): for attempt in range(4): try: req = urllib.request.Request(URL.format(off), headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=60) as r: return json.load(r) except Exception as e: # noqa: BLE001 print("retry", off, e, file=sys.stderr) time.sleep(5 * (attempt + 1)) raise SystemExit("failed at offset %d" % off) def main(): out, off, total = [], 0, None started = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec="seconds") while total is None or off < total: d = get(off) total = d["pagination"]["total"] for it in d["items"]: out.append({ "resource": it.get("resource"), "service": it.get("serviceName"), "desc": (it.get("description") or "")[:160], "lastUpdated": it.get("lastUpdated"), "quality": it.get("quality"), "accepts": [{k: a.get(k) for k in ("network", "scheme", "amount", "maxAmountRequired", "asset", "payTo")} for a in it.get("accepts", [])], }) off += 1000 print(off, total, len(out), file=sys.stderr) time.sleep(1) fn = "raw/bazaar_%s.json" % started[:10] json.dump({"source": URL.format("N"), "fetched_utc": started, "total_reported": total, "items": out}, open(fn, "w", encoding="utf-8")) print(fn, len(out), total) if __name__ == "__main__": main()