// Signs an x402 payment for one site-report request and prints the PAYMENT-SIGNATURE header value (used by ../curl.sh). // Usage: BUYER_PRIVATE_KEY=0x... node sign-payment.mjs '' // It sends the request once without payment, reads the 402 terms and signs exactly those (USDC, scheme exact). // Nothing is paid until you send the signature; an answer >= 400 to the paid request is never settled. // MAX_PRICE_USD (default 1) refuses to sign anything more expensive. Needs @x402/fetch, @x402/evm and viem. import { x402Client, x402HTTPClient } from '@x402/fetch'; import { registerExactEvmScheme } from '@x402/evm/exact/client'; import { privateKeyToAccount } from 'viem/accounts'; const [endpoint, body] = process.argv.slice(2); const key = process.env.BUYER_PRIVATE_KEY; const max = Number(process.env.MAX_PRICE_USD || 1); if (!endpoint || !body || !key) { console.error('Usage: BUYER_PRIVATE_KEY=0x... node sign-payment.mjs '); process.exit(2); } const res = await fetch(endpoint, { method: 'POST', headers: { 'content-type': 'application/json' }, body }); if (res.status !== 402) { console.error(`Expected 402 with payment terms, got ${res.status}: ${await res.text()}`); process.exit(1); } const client = new x402Client(); registerExactEvmScheme(client, { signer: privateKeyToAccount(key) }); const http = new x402HTTPClient(client); const terms = http.getPaymentRequiredResponse(name => res.headers.get(name), await res.json().catch(() => null)); const offer = terms.accepts?.[0]; const usd = Number(offer?.amount) / 1e6; // USDC has 6 decimals if (!(usd > 0) || usd > max) { console.error(`Refusing to sign: the price is ${usd} USD, above MAX_PRICE_USD ${max}.`); process.exit(1); } console.error(`Signing ${usd} USD (USDC) to ${offer.payTo} on ${offer.network}.`); const headers = http.encodePaymentSignatureHeader(await client.createPaymentPayload(terms)); process.stdout.write(headers['PAYMENT-SIGNATURE'] || headers['X-PAYMENT']);