#!/usr/bin/env node
// Pay PayGuard's Stellar testnet x402 route and print the result + settlement tx.
// STELLAR_SECRET_FILE=/path/with/secret=S... node scripts/stellar-testnet-pay.mjs [url]
// The payer only needs testnet XLM (Friendbot: https://friendbot.stellar.org/?addr=G...); the facilitator sponsors fees.
import { readFileSync } from 'node:fs';
import { x402Client, wrapFetchWithPayment, decodePaymentResponseHeader } from '@x402/fetch';
import { createEd25519Signer } from '@x402/stellar';
import { ExactStellarScheme } from '@x402/stellar/exact/client';
const url = process.argv[2] || 'https://api.youraitools.co/payguard/stellar-testnet/v1/address?address=0x098B716B8Aaf21512996dC57EB0615e2383E2f96';
const secret = readFileSync(process.env.STELLAR_SECRET_FILE, 'utf8').match(/^secret=(S[A-Z2-7]{55})$/m)[1];
const signer = createEd25519Signer(secret, 'stellar:testnet');
console.log('payer', signer.address);
// XLM (native SAC) is not a default x402 asset, so opt in to exactly this asset with a 0.1 XLM cap.
const XLM_SAC = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC';
const client = x402Client.fromConfig({
schemes: [{ network: 'stellar:testnet', client: new ExactStellarScheme(signer) }],
spendControls: { allowedAssets: [{ network: 'stellar:testnet', asset: XLM_SAC, maxAmountPerPayment: '1000000' }] },
});
const pay = wrapFetchWithPayment(fetch, client);
const t0 = Date.now();
const res = await pay(url, { headers: { accept: 'application/json' } });
const text = await res.text();
console.log('status', res.status, `${Date.now() - t0} ms`);
const pr = res.headers.get('payment-response');
if (pr) {
const s = decodePaymentResponseHeader(pr);
console.log('settlement', JSON.stringify(s));
if (s.transaction) console.log('explorer', `https://stellar.expert/explorer/testnet/tx/${s.transaction}`);
}
const req = res.headers.get('payment-required');
if (res.status === 402 && req) { try { console.log('402 reason', JSON.parse(Buffer.from(req, 'base64').toString()).error); } catch {} }
console.log(text.slice(0, 1500));
process.exit(res.ok ? 0 : 1);
agentgate-source: code mirror on Cloudflare Pages. All repos