بنقرة واحدة
x402-payments-stellar-edition
Build paid APIs and agent payment clients on Stellar using the x402 protocol with USDC
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Build paid APIs and agent payment clients on Stellar using the x402 protocol with USDC
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | x402 Payments — Stellar Edition |
| description | Build paid APIs and agent payment clients on Stellar using the x402 protocol with USDC |
Build paid APIs and agent payment infrastructure on Stellar using the x402 protocol. Deploy with USDC on Soroban — fee-free for clients via the OZ Channels facilitator. Sub-5s settlement.
x402 is an open payment protocol (by Coinbase) built on the HTTP 402 status code. Any API can charge per-request in USDC — no API keys, no subscriptions, no accounts. Clients (humans or AI agents) pay at the moment of use, and the server verifies payment before granting access.
Client → GET /api/data → Server
Client ← 402 Payment Required (pricing + Stellar requirements) ← Server
Client → GET /api/data + X-PAYMENT header (signed auth entries) → Server
Server → verifies via Facilitator → settles USDC on Stellar
Client ← 200 OK (data) ← Server
On Stellar, the payment flow uses Soroban smart contracts:
stellar:testnet or stellar:pubnet networktransfer invocationX-PAYMENT header (Base64-encoded JSON)When a user asks for x402 help on Stellar, determine three things:
stellar:testnet + OZ Channels testnet facilitatorstellar:pubnet + production facilitatorMonetize an Express API with x402 — fee-free for clients (facilitator covers fees):
npm install @x402/express @x402/core express
import express from "express";
import { paymentMiddleware } from "@x402/express";
const app = express();
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "stellar:testnet",
payTo: process.env.STELLAR_PAY_TO_ADDRESS!, // your G... address
},
],
description: "Weather report",
},
},
{
url: "https://channels.openzeppelin.com/x402/testnet",
headers: process.env.OZ_RELAYER_API_KEY
? { "x-api-key": process.env.OZ_RELAYER_API_KEY }
: undefined,
}
)
);
app.get("/weather", (_req, res) => {
res.json({
city: "London",
temperature: 22,
conditions: "Partly cloudy",
timestamp: Date.now(),
});
});
app.listen(3000, () => console.log("x402 server on http://localhost:3000"));
Set STELLAR_PAY_TO_ADDRESS (your G... address) and optionally OZ_RELAYER_API_KEY. Clients sign auth entries (e.g. with Freighter); no XLM needed.
Prerequisites: Your agent needs a funded Stellar wallet with a USDC trustline. See
references/wallet-setup.mdfor the one-time setup (keypair → XLM → trustline → USDC).
Call a paid x402 endpoint from an AI agent or Node.js script:
npm install @stellar/stellar-sdk node-fetch
import { Keypair, Networks, Contract, Address, nativeToScVal, TransactionBuilder, rpc as StellarRpc, contract } from "@stellar/stellar-sdk";
const RPC_URL = "https://soroban-testnet.stellar.org";
const rpcServer = new StellarRpc.Server(RPC_URL);
// Step 1: Call the paid endpoint — get 402 challenge
const response = await fetch("https://api.example.com/weather");
if (response.status !== 402) {
console.log("No payment required:", await response.json());
process.exit(0);
}
const challenge = await response.json();
// challenge = { x402Version: 2, accepts: [{ scheme, network, amount, payTo, asset, ... }] }
const accept = challenge.accepts[0];
// Step 2: Build Soroban USDC transfer
const keypair = Keypair.fromSecret(process.env.STELLAR_SECRET_KEY!);
const publicKey = keypair.publicKey();
const tx = await contract.AssembledTransaction.build({
contractId: accept.asset,
method: "transfer",
args: [
nativeToScVal(publicKey, { type: "address" }),
nativeToScVal(accept.payTo, { type: "address" }),
nativeToScVal(BigInt(accept.amount), { type: "i128" }),
],
networkPassphrase: Networks.TESTNET,
rpcUrl: RPC_URL,
parseResultXdr: (r: any) => r,
});
// Step 3: Sign auth entries (not the full transaction)
const signer = contract.basicNodeSigner(keypair, Networks.TESTNET);
const latestLedger = (tx.simulation as any).latestLedger;
await tx.signAuthEntries({
address: publicKey,
signAuthEntry: signer.signAuthEntry,
expiration: latestLedger + 12, // ~1 minute
});
// Step 4: Re-simulate in Enforcing mode
await tx.simulate();
const finalXDR = tx.built!.toXDR();
// Step 5: Build X-PAYMENT header
const payload = Buffer.from(JSON.stringify({
x402Version: 2,
accepted: accept,
payload: { transaction: finalXDR },
})).toString("base64");
// Step 6: Retry with payment
const paidResponse = await fetch("https://api.example.com/weather", {
headers: { "X-PAYMENT": payload },
});
console.log("Paid response:", await paidResponse.json());
For full control over the x402 flow (custom facilitator, rollout gates, pricing tiers):
import type { Request, Response, NextFunction } from "express";
interface PaymentRequirements {
scheme: "exact";
network: string; // "stellar:pubnet" or "stellar:testnet"
amount: string; // atomic units (7 decimals for Stellar USDC)
payTo: string; // G... address
maxTimeoutSeconds: number;
asset: string; // Soroban SAC USDC contract ID
extra: { areFeesSponsored: boolean };
}
// Build 402 challenge response
const buildChallenge = (req: Request, amount: string, payTo: string) => ({
x402Version: 2,
resource: {
url: `https://${req.get("host")}${req.originalUrl}`,
description: "Premium API access",
mimeType: "application/json",
},
accepts: [{
scheme: "exact",
network: process.env.STELLAR_NETWORK || "stellar:testnet",
amount,
payTo,
maxTimeoutSeconds: 300,
asset: process.env.STELLAR_USDC_ASSET!,
extra: { areFeesSponsored: true },
}],
});
// Middleware
export const requirePayment = (amountAtomic: string) => {
return async (req: Request, res: Response, next: NextFunction) => {
const paymentHeader = req.header("X-PAYMENT");
// No payment → return 402 challenge
if (!paymentHeader) {
res.status(402).json(buildChallenge(req, amountAtomic, process.env.STELLAR_PAY_TO!));
return;
}
// Parse payment payload
let parsed;
try {
const decoded = Buffer.from(paymentHeader, "base64").toString("utf8");
parsed = JSON.parse(decoded);
} catch {
res.status(401).json({ error: "Invalid X-PAYMENT header" });
return;
}
// Verify + settle via facilitator
const facilitatorUrl = process.env.FACILITATOR_URL || "https://channels.openzeppelin.com/x402/testnet";
const verifyRes = await fetch(`${facilitatorUrl}/verify`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
paymentPayload: parsed,
paymentRequirements: buildChallenge(req, amountAtomic, process.env.STELLAR_PAY_TO!).accepts[0],
}),
});
const verify = await verifyRes.json() as any;
if (!verify.isValid) {
res.status(401).json({ error: verify.invalidReason || "Payment invalid" });
return;
}
const settleRes = await fetch(`${facilitatorUrl}/settle`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
paymentPayload: parsed,
paymentRequirements: buildChallenge(req, amountAtomic, process.env.STELLAR_PAY_TO!).accepts[0],
}),
});
const settle = await settleRes.json() as any;
if (!settle.success) {
res.status(502).json({ error: settle.errorReason || "Settlement failed" });
return;
}
// Payment successful — attach context
(req as any).paymentContext = {
payer: settle.payer,
txHash: settle.transaction,
network: settle.network,
};
next();
};
};
| Testnet | Mainnet | |
|---|---|---|
| Network ID | stellar:testnet | stellar:pubnet |
| RPC URL | https://soroban-testnet.stellar.org | https://mainnet.sorobanrpc.com |
| Facilitator | https://channels.openzeppelin.com/x402/testnet | https://channels.openzeppelin.com/x402 |
| Facilitator API Key | Generate testnet key | Generate mainnet key |
| USDC Contract | Testnet SAC address | CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75 |
| Token | Testnet USDC (free from faucets) | Real USDC |
| Funding | Stellar Friendbot | Regular account funding |
Always start on testnet. Switch to mainnet by changing the network string and RPC URL.
curl "https://friendbot.stellar.org?addr=YOUR_PUBLIC_KEY"
Use the Stellar Laboratory or the testnet faucet to get USDC tokens.
STELLAR_PAY_TO_ADDRESS=GXXX... \
STELLAR_NETWORK=stellar:testnet \
npm run dev
curl -s http://localhost:3000/weather | jq .
# → { x402Version: 2, accepts: [{ scheme: "exact", network: "stellar:testnet", ... }] }
STELLAR_SECRET_KEY=SXXX... \
npm start
# → Paid response: { city: "London", ... }
exact = fixed price per request.stellar:pubnet = Stellar mainnet. stellar:testnet = testnet.max_ledger expiration bounds instead of full transactions.references/wallet-setup.md — Agent wallet setup (keypair, trustline, USDC funding)references/stellar.md — Complete Stellar setup (Soroban, Freighter, OZ Channels, auth entries)references/facilitator.md — Facilitator routing (verify / settle / supported)references/packages.md — All npm packages