# Site report from Python: free status/price check, pay with the x402 client, poll, save the client-ready files. # pip install "x402[requests,evm]" eth_account requests # SHOP=http://127.0.0.1:4999 TARGET=https://lordevo.com BUYER_PRIVATE_KEY=0x... python site_report.py # SHOP defaults to a local dev shop (dry mode, mock facilitator: no real money). For the real shop use # SHOP=https://shop.lordevo.com and a key holding USDC on Base, only once the service is on sale. # Same x402 package and requests client as the shop's Python guides (https://shop.lordevo.com/guides/python and # /guides/langchain-python). # NOTE: this file was not executed by the shop's test suite (no Python on the test machine); the curl and Node examples were. import json import os import sys import time import requests from eth_account import Account from x402 import x402ClientSync from x402.http.clients import x402_requests from x402.mechanisms.evm import EthAccountSigner from x402.mechanisms.evm.exact.register import register_exact_evm_client SHOP = os.environ.get("SHOP", "http://127.0.0.1:4999").rstrip("/") TARGET = os.environ.get("TARGET", "https://lordevo.com") OUT = os.environ.get("OUT_DIR", ".") # 1. Free: status, price and endpoint from the shop's catalog (no wallet). catalog = requests.get(f"{SHOP}/catalog.json", timeout=30).json() svc = next(s for s in catalog["services"] if s["slug"] == "site-report") tier = next(t for t in svc["tiers"] if t["id"] == "standard") price = "to be confirmed" if svc.get("price_status") else f'{tier["price_usd"]} USD' print(f'site-report: {svc["status"]}; price {price}; on sale: {tier["on_sale"]}') if not tier["on_sale"]: sys.exit(0) # 2. A requests.Session that answers HTTP 402 with a signed USDC payment and retries once. client = x402ClientSync() register_exact_evm_client(client, EthAccountSigner(Account.from_key(os.environ["BUYER_PRIVATE_KEY"]))) pay = x402_requests(client) # 3. The request. Bad input is never charged: an unpaid request gets the 402 with input_hint, a paid one a 400 (also 403/429). body = { "url": TARGET, "scope": {"max_pages": int(os.environ.get("MAX_PAGES", "10")), "audience": "agency", "format": "all"}, "authorization": {"attested": True, "statement": "I own this website or have written permission from its owner to assess it."}, } if os.environ.get("BRAND_NAME"): body["scope"]["brand"] = {"name": os.environ["BRAND_NAME"]} if os.environ.get("BRAND_LOGO_URL"): body["scope"]["brand"]["logo_url"] = os.environ["BRAND_LOGO_URL"] r = pay.post(tier["endpoint"], json=body, timeout=120) j = r.json() if r.status_code >= 400: print(f'HTTP {r.status_code} {j.get("error")}: {j.get("message", "")} (charged: {j.get("charged", False)})', file=sys.stderr) sys.exit(1) print(f'HTTP {r.status_code}, status {j["status"]}, delivery {j["delivery_id"]}') # 4. 202 = running (already charged: something was measured). Poll result_url for free every 15-30 s. while j["status"] == "running": print(f'running: {j.get("progress", "")}') time.sleep(20) j = requests.get(j["result_url"], timeout=30).json() if j["status"] != "done": print(f'Report {j["status"]}: {j.get("error", "")} Keep delivery_id {j["delivery_id"]} as your reference.', file=sys.stderr) sys.exit(1) # 5. Save the JSON and the client-ready documents (private links, 30 days). os.makedirs(OUT, exist_ok=True) with open(os.path.join(OUT, "report.json"), "w", encoding="utf-8") as f: json.dump(j["report"], f, indent=2) for name, url in (("report.html", j["report_html_url"]), ("report.md", j["report_markdown_url"])): d = requests.get(url, timeout=30) d.raise_for_status() with open(os.path.join(OUT, name), "w", encoding="utf-8") as f: f.write(d.text) print(j["report"]["summary"]["executive_summary"]) print(f'saved report.json, report.html, report.md in {os.path.abspath(OUT)}')