BASE MAINNET · USDC · NO SIGNUP · $0.005 PER USE
A working payment in 3 steps
Use the official x402 buyer SDK to fetch live Binance + Bybit funding rates from Bounty Engineer. First validate the quote for free. Only a separate, explicit --pay flag permits ONE purchase with the buyer's own authorized wallet. No seller access to the wallet.
Free live data sample · Stripe agent payments · All API contracts · Raw Node.js script
1. Install Node.js 20+ and dependencies:
npm install @x402/fetch @x402/evm viem
2. Get the buyer script and run dry:
curl -fsS https://bounty-engineer-x402-prod.onrender.com/buyer-quickstart.mjs -o buyer-quickstart.mjs node buyer-quickstart.mjs
3. Only if you independently approve the price and need the result, set BUYER_BASE_PRIVATE_KEY locally and call:
node buyer-quickstart.mjs --pay
Funding Base USDC and a small amount of gas may be necessary for the buyer wallet. Your agent must use its own spending policy. Never place secrets in URLs, chats or webpages. A free sample does not constitute a paid purchase.
Full auditable source
import {wrapFetchWithPaymentFromConfig} from "@x402/fetch";
import {ExactEvmScheme} from "@x402/evm";
import {privateKeyToAccount} from "viem/accounts";
// NODE >=20. Run in dry-run mode by default. To authorize precisely ONE
// transaction, add --pay and a caller-owned, funded Base wallet ENV secret.
// NEVER give the merchant your key or use a seller wallet here.
const ORIGIN="https://bounty-engineer-x402-prod.onrender.com";
const ENDPOINT=ORIGIN+"/v1/funding-rates";
const PAY_TO="0xf0c39261192686cdcce529b9919a37863de4c77c";
const BASE_CHAIN="eip155:8453";
const BASE_USDC="0x833589fcD6eDb6E08f4c7c32d4f71b54bdA02913".toLowerCase();
const MAX_MICROUSDC=5_000n; // $0.005 hard cap, USDC has 6 decimals.
const requested={symbol:"BTCUSDT",providers:["binance","bybit"]};
const body=JSON.stringify(requested);
const approve=process.argv.includes("--pay");
const probe=await fetch(ENDPOINT,{
method:"POST",headers:{"content-type":"application/json"},body
});
if(probe.status!==402)throw Error("Merchant did not return 402; abort");
const challenge=probe.headers.get("PAYMENT-REQUIRED");
if(!challenge)throw Error("No official PAYMENT-REQUIRED; abort");
const message=JSON.parse(Buffer.from(challenge,"base64").toString("utf8"));
const options=Array.isArray(message.accepts)?message.accepts:[];
const matched=options.find(p=>
p.network===BASE_CHAIN &&
p.payTo?.toLowerCase()===PAY_TO &&
p.asset?.toLowerCase()===BASE_USDC &&
BigInt(String(p.amount??p.maxAmountRequired??"-1"))>0n &&
BigInt(String(p.amount??p.maxAmountRequired??"-1"))<=MAX_MICROUSDC
);
if(!matched)throw Error("Expected merchant payee, Base USDC and $0.005 max price did not match");
console.log("Verified Base USDC quote:", {
endpoint:ENDPOINT,network:matched.network,
price_usdc:Number(BigInt(String(matched.amount??matched.maxAmountRequired)))/1_000_000,
payee:matched.payTo
});
if(!approve){console.log("DRY RUN. To make ONE authorized purchase, use --pay.");process.exit(0);}
const key=process.env.BUYER_BASE_PRIVATE_KEY;
if(!key || !/^0x[a-f0-9]{64}$/i.test(key))
throw Error("Set BUYER_BASE_PRIVATE_KEY only in your own local environment");
const account=privateKeyToAccount(key);
const paymentFetch=wrapFetchWithPaymentFromConfig(fetch,{
schemes:[{network:BASE_CHAIN,client:new ExactEvmScheme(account)}],
paymentRequirementsSelector:(_version,accepts)=>{
const p=accepts.find(a=>
a.network===matched.network &&
a.payTo?.toLowerCase()===PAY_TO &&
a.asset?.toLowerCase()===BASE_USDC &&
BigInt(String(a.amount??a.maxAmountRequired??"-1"))===BigInt(String(matched.amount??matched.maxAmountRequired))
);
if(!p)throw Error("Paid challenge changed between quote and signing");
return p;
}
});
const response=await paymentFetch(ENDPOINT,{
method:"POST",headers:{"content-type":"application/json"},body
});
if(!response.ok)throw Error("Purchase not fulfilled: HTTP "+response.status);
if(!response.headers.get("PAYMENT-RESPONSE"))
throw Error("Successful HTTP response lacks settled x402 payment receipt");
console.log("Authorized paid result:",await response.json());