Як розпочати роботу з x402 на Solana

Що таке x402?

x402 — це відкритий протокол для нативних інтернет-платежів. Код помилки 402 означає "Payment Required" (оплата обов'язкова) і існує вже давно у специфікаціях HTTP, проте лише зараз його стало реально застосовувати завдяки розвитку блокчейн-мереж. Протокол 402 реалізує шаблон HTTP 402 Payment Required: сервер вимагає оплату перед поверненням захищеної відповіді. На Solana це зазвичай реалізується шляхом запиту до клієнта на виконання невеликого переказу, після чого сервер перевіряє транзакцію в мережі та надає доступ до контенту.

На даний момент ще не зрозуміло, який із 402 SDK стане найпопулярнішим. Тому в цьому посібнику ми покажемо, як реалізувати x402 за допомогою мінімального сервера та клієнта, а також наведемо перелік усіх доступних 402 SDK з описом їхньої поточної підтримки Solana.

Як це працює?

Існує кілька способів реалізації x402 — від гранично спрощених до повністю керованих.

Ідея протоколу: Використовуйте звичайний HTTP. Клієнт звертається до вашого URL → ви відповідаєте 402 Payment Required з JSON-об'єктом Payment Requirements → клієнт здійснює оплату та повторює запит із заголовком X-PAYMENT → ви перевіряєте/проводите транзакцію → відповідаєте 200 OK. Без облікових записів, без OAuth.

Діаграма потоку x402Діаграма потоку x402

Примітка: Фасилітатор є повністю необов'язковим, і ви також можете реалізувати власну логіку перевірки за допомогою кількох рядків коду. Фасилітатор абстрагує деталі інтеграції з блокчейном від сервера та клієнта, що спрощує реалізацію.

Ключові елементи специфікації: структура PaymentRequirements, заголовок X-PAYMENT у кодуванні base64, необов'язковий X-PAYMENT-RESPONSE у разі успіху, а також (опціональний) API фасилітатора для /verify, /settle, /supported. Поточна конкретна схема — exact (оплата фіксованої суми). Інші варіанти, наприклад upto, перебувають у стадії пропозиції.

Підтримка Solana: сам протокол є незалежним від мережі; на Solana він підтримує всі токени SPL. Підтримка Solana доступна або перебуває в розробці для більшості 402 SDK.

Нижче наведено перелік доступних 402 SDK з описом їхньої поточної підтримки Solana.

Варіанти використання

x402 відкриває широкий спектр сценаріїв мікроплатежів і моделі оплати за використання, які раніше були економічно нежиттєздатними без блокчейну. Уявіть, що Netflix платить за кожний перегляд або Spotify — за кожну пісню замість підписки. Ось кілька можливих ідей, але весь спектр можливостей відкритий для уяви:

ШІ та агентна комерція:

  • Доступ до API ШІ-агентів: Оплата за кожне звернення до LLM, генерацію зображень або виклик API ШІ-моделі (Дивіться приклад ACK)
  • Монетизація MCP-серверів: Стягнення плати за інструменти Model Context Protocol, джерела даних та спеціалізовані можливості агентів (Дивіться MCPay.tech)
  • Платежі між агентами: Забезпечення автономних транзакцій між агентами за послуги та дані (Дивіться приклад a2a-x402)
  • Преміальні навчальні дані для ШІ: Продаж доступу до відібраних наборів даних на основі оплати за запит

Контент і медіа:

  • Статті за paywall: Стягнення мікросум за статтю замість повної підписки
  • Відео/аудіостримінг: Оплата за перегляд або за хвилину контенту
  • Зображення у високій роздільній здатності: Розблокування завантажень у повній роздільній здатності після оплати (дивіться приклад ACK) або приклад x402 coinbase
  • Доступ до преміальних розсилок: Монетизація окремих випусків розсилки

Сервіси для розробників:

  • Тарифікація API: Оплата за RPC-виклик, запит до бази даних або обчислювальну одиницю (Дивіться приклад Corbits)
  • Serverless-функції: Стягнення плати за окремі виклики функцій

Дані та аналітика:

  • Ринкові дані в реальному часі: Тарифікація за котирування або тік
  • Аналітичні дашборди: Розблокування конкретних звітів або експорту даних
  • Дані IoT-сенсорів: Мікроплатежі за показники сенсорів із мереж DePIN

Ігри та віртуальні товари:

  • Доступ до ігрових серверів: Оплата за сесію або за годину
  • Завантаження модів/ресурсів: Монетизація контенту, створеного користувачами
  • Внески за участь у турнірах: Автоматизований розподіл призового фонду

Різне:

  • Фільтрація електронної пошти/повідомлень: Вимога оплати для доступу до вашої скриньки (захист від спаму)
  • Обчислювальні ресурси: Оплата за годину CPU, хвилину GPU або ГБ сховища
  • VPN/проксі-доступ: Тарифікація за ГБ трафіку
  • Одноразові завантаження файлів: Продаж цифрових файлів без накладних витрат на підписку (Дивіться приклад ACK)

Ключова перевага x402 на Solana — низькі витрати на транзакції (частки цента), що робить справжні мікроплатежі реальними, а також миттєвий розрахунок, що забезпечує контроль доступу в реальному часі.

SDK та їхня підтримка Solana

Це список, що постійно оновлюється — він буде доповнюватися в міру появи нових SDK або додавання підтримки Solana.

SDK / ПроєктПідтримка SolanaПриміткиДокументація / URL
CorbitsТакЗручний SDK для 402 на SolanaДокументація
MCPay.techТакОплата за MCP-сервери за допомогою мікроплатежівСайт
PayAI FacilitatorТакФасилітатор x402 з підтримкою Solanapayai.network
CoinbaseТак / Python у розробціРеференсна реалізація протоколу x402 від CoinbaseGitHub
ACKУ PRПротокол агентних платежів із підтримкою x402GitHub
CrossmintУ розробціПлатежі, гаманці; агентні фінанси; не специфічно для x402crossmint.com
A2A x402 (Google)У розробціПлатежі між агентами з використанням Google AIGitHub
Nexus (Thirdweb)У розробціОбгортка x402 навколо API-ключівNexus
x402scanН/Д (Оглядач)Оглядач екосистеми x402 (не SDK)x402scan.com
Нативний прикладТакМінімальний приклад без залежностейПриклади

Corbits

SDK з пріоритетом на Solana для швидкої реалізації x402-потоків на Solana. Дивіться документацію: https://corbits.dev/

Приклад, що дозволяє оплачувати RPC-запити до Solana.

npm install @faremeter/payment-solana @faremeter/fetch @faremeter/info
@solana/web3.js

Створіть файл payer-wallet.json і поповніть його певною кількістю USDC та mainnet SOL.

import {
Keypair,
PublicKey,
VersionedTransaction,
Connection
} from "@solana/web3.js";
import { createPaymentHandler } from "@faremeter/payment-solana/exact";
import { wrap } from "@faremeter/fetch";
import { lookupKnownSPLToken } from "@faremeter/info/solana";
import * as fs from "fs";
// Load keypair from file
const keypairData = JSON.parse(fs.readFileSync("./payer-wallet.json", "utf-8"));
const keypair = Keypair.fromSecretKey(Uint8Array.from(keypairData));
const network = "mainnet-beta";
const connection = new Connection("https://api.mainnet.solana.com");
const usdcInfo = lookupKnownSPLToken(network, "USDC");
const usdcMint = new PublicKey(usdcInfo.address);
// Create wallet interface
const wallet = {
network,
publicKey: keypair.publicKey,
updateTransaction: async (tx: VersionedTransaction) => {
tx.sign([keypair]);
return tx;
}
};
// Setup payment handler
const handler = createPaymentHandler(wallet, usdcMint, connection);
const fetchWithPayer = wrap(fetch, { handlers: [handler] });
// Call the API - payment happens automatically
const response = await fetchWithPayer("https://helius.api.corbits.dev", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getBlockHeight"
})
});
const data = await response.json();
console.log(data);
npx tsx e2e.ts

Це дозволить оплатити RPC-запит і повернути висоту блоку, використовуючи протокол corbits 402.

Coinbase

Референсна реалізація від Coinbase протоколу x402 надає бібліотеки TypeScript та приклади як для клієнтського, так і для серверного потоків. Репозиторій включає наскрізні тести, що охоплюють 6 різних сценаріїв SVM (Solana Virtual Machine). Реалізація охоплює перевірку платежів, генерацію квитанцій та обробку помилок.

Ключові можливості:

  • Реалізації клієнта та сервера на TypeScript
  • Утиліти для перевірки платежів
  • Підтримка кількох схем оплати (точна сума, сума «до»)
  • Набір тестів із прикладами транзакцій Solana
  • Розділення між логікою протоколу та бізнес-логікою

Простий у використанні приклад із мінімальним сервером і клієнтом можна знайти тут.

const app = express();
const PORT = 3000;
// Apply x402 payment middleware
// This automatically handles:
// - 402 responses with payment requirements
// - Payment verification (pre-flight checks)
// - Transaction submission via facilitator
// - Settlement confirmation
app.use(
paymentMiddleware(RECIPIENT, {
// Protected endpoint: requires $0.001 USDC payment
"GET /premium": {
price: "$0.0001", // Price in USD (converted to USDC)
network: "solana-devnet" // Solana devnet
},
// Another endpoint with different price
"GET /expensive": {
price: "$0.001",
network: "solana-devnet"
}
})
);
// Protected endpoints - only accessible after payment
app.get("/premium", (req, res) => {
res.json({
message: "🎉 Premium content accessed!",
data: {
secret: "This is premium content",
timestamp: new Date().toISOString()
}
});
});

Підтримка Python перебуває в розробці; робочий наскрізний приклад доступний тут.

ACK

Agent Commerce Kit (ACK) підтримує протокол x402, але додає критично важливі рівні для агентної економіки: верифіковану ідентичність агента (ACK-ID) з використанням W3C DID/VC та криптографічно захищені квитанції (ACK-Pay) як Verifiable Credentials. Це дозволяє агентам підтверджувати власність, автентифікуватися автономно та генерувати платіжні докази, готові до комплаєнсу, вирішуючи кризу ідентичності та транзакційні бар'єри, що заважають ШІ-агентам брати участь у комерції.

Діаграма потоку ACKДіаграма потоку ACK

Є PR із наскрізним прикладом, який ще не злито, але він працює. Також є живий приклад, що демонструє, як встановити paywall для зображень, джукбокс та API для анімації зображень. Вихідний код прикладів разом із Twitter-ботом, який використовує API для анімації зображень у стрічці, можна знайти тут.

MCPay.tech

Мікроплатежі за запит для MCP (Model Context Protocol) серверів з використанням x402-подібних потоків. Дозволяє розробникам монетизувати MCP-інструменти та ресурси, вимагаючи невеликої оплати за кожен виклик API або інструменту, спрощуючи стягнення плати за доступ ШІ-агентів до преміальних джерел даних, спеціалізованих інструментів або обчислювальних ресурсів. Сайт: https://mcpay.tech/

PayAI Facilitator

Фасилітатор x402 з пріоритетом на Solana з живим тестовим мерчантом-ехо для тестування та повернення платежів. PayAI наразі бере на себе всі комісії за транзакції. Сайт: https://payai.network/

A2A x402 (Google)

Ініціатива платежів між агентами за протоколом 402, що досліджує стандартизовані потоки payment-required. Підтримка Solana наразі в процесі розробки, а робочий приклад чату можна знайти тут

Crossmint

Crossmint — це комплексна платформа для компаній та агентів для інтеграції криптоінфраструктури, включаючи гаманці, onramp-и, оркестрацію стейблкоїнів тощо. Підтримка x402 на Solana наразі в розробці і має бути завершена до 30.10.2025. Сайт: https://www.crossmint.com/

x402scan

Оглядач екосистеми x402, що надає вичерпну статистику, перелік проєктів та аналітику для реалізацій x402. Відстежуйте обсяги транзакцій, знаходьте активних мерчантів та моніторте зростання ендпоїнтів з вимогою оплати в різних мережах. Сайт: https://x402scan.com/

Nexus (Thirdweb)

Thirdweb Nexus розробляє обгортку x402 навколо API-ключів (наразі в розробці). Сайт: https://nexus.thirdweb.com/

Нативний приклад

Нативний приклад без залежностей із мінімальним сервером і клієнтом.

Ви можете клонувати репозиторій і запустити приклад:

git clone https://github.com/Woody4618/x402-solana-examples
npm install
# Terminal 1: Start server
npm run usdc:server
# Terminal 2: Run client (requires devnet USDC)
npm run usdc:client

Огляд потоку

  1. Клієнт надсилає запит до /premium.
  2. Сервер відповідає 402 з умовами оплати: одержувач, сума.
  3. Клієнт створює транзакцію з інструкцією переказу одержувачу.
  4. Клієнт повторює запит до /premium з payload транзакції.
  5. Сервер перевіряє транзакцію та відправляє її до мережі.
  6. Після підтвердження сервер відповідає 200.

Альтернатива для Solana: У Solana можна реалізувати варіант, де клієнт надсилає транзакцію безпосередньо в мережу з інструкцією memo (замість того, щоб надсилати її на сервер), а потім передає лише підпис транзакції на сервер для перевірки. Це вирішує проблему розриву з'єднання — якщо клієнт відключається після оплати, але до отримання контенту, він може повторити запит із тим самим підписом, оскільки платіж уже підтверджено в блокчейні. Однак цей підхід відхиляється від стандартного потоку x402.org (який передбачає, що сервер транслює транзакцію), тому в цьому прикладі ми використовуємо стандартний підхід.

Примітка: Код цього прикладу не пройшов аудит, не готовий до використання у виробничому середовищі та призначений лише для демонстраційних цілей. Він показує, що x402 можна реалізувати без залежностей і без використання фасилітатора. Використання фасилітатора зручне тим, що він приховує складність і може взяти на себе комісію за транзакції, але він також може бути єдиною точкою відмови — наприклад, коли на гаманці фасилітатора закінчуються кошти. Приклад сервера надсилає транзакції, підписані клієнтом. Можливо, вам знадобиться їх перевірити.

Мінімальний сервер (Express)

// x402-compliant server with USDC (SPL Token) payments
import express from "express";
import { Connection, PublicKey, Transaction } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddress } from "@solana/spl-token";
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
// Devnet USDC mint address
const USDC_MINT = new PublicKey("4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU");
// Your recipient wallet address (same as SOL example)
const RECIPIENT_WALLET = new PublicKey(
"seFkxFkXEY9JGEpCyPfCWTuPZG9WK6ucf95zvKCfsRX"
);
// Derive the recipient's USDC token account (Associated Token Account)
const RECIPIENT_TOKEN_ACCOUNT = await getAssociatedTokenAddress(
USDC_MINT,
RECIPIENT_WALLET
);
// Picking a small USDC price
const PRICE_USDC = 100; // 0.0001 USDC
const app = express();
app.use(express.json());
// x402 endpoint - Quote or verify payment
app.get("/premium", async (req, res) => {
const xPaymentHeader = req.header("X-Payment");
// If client provided X-Payment header, verify and submit transaction
if (xPaymentHeader) {
try {
// Decode base64 and parse JSON (x402 standard)
const paymentData = JSON.parse(
Buffer.from(xPaymentHeader, "base64").toString("utf-8")
) as {
x402Version: number;
scheme: string;
network: string;
payload: {
serializedTransaction: string;
};
};
console.log("Received USDC payment proof from client");
console.log(` Network: ${paymentData.network}`);
// Deserialize the transaction
const txBuffer = Buffer.from(
paymentData.payload.serializedTransaction,
"base64"
);
const tx = Transaction.from(txBuffer);
console.log("Verifying SPL Token transfer instructions...");
// Step 1: Introspect and decode SPL Token transfer instruction
const instructions = tx.instructions;
let validTransfer = false;
let transferAmount = 0;
for (const ix of instructions) {
// Check if this is a Token Program instruction
if (ix.programId.equals(TOKEN_PROGRAM_ID)) {
// SPL Token Transfer instruction layout:
// [0] = instruction type (3 for Transfer)
// [1-8] = amount (u64, little-endian)
if (ix.data.length >= 9 && ix.data[0] === 3) {
// Read the amount (u64 in little-endian, starts at byte 1)
transferAmount = Number(ix.data.readBigUInt64LE(1));
// Verify accounts: [source, destination, owner]
if (ix.keys.length >= 2) {
const destAccount = ix.keys[1].pubkey;
if (
destAccount.equals(RECIPIENT_TOKEN_ACCOUNT) &&
transferAmount >= PRICE_USDC
) {
validTransfer = true;
console.log(
` ✓ Valid USDC transfer: ${transferAmount / 1000000} USDC`
);
console.log(` To: ${RECIPIENT_TOKEN_ACCOUNT.toBase58()}`);
break;
}
}
}
}
}
if (!validTransfer) {
return res.status(402).json({
error:
"Transaction does not contain valid USDC transfer to recipient with correct amount",
details:
transferAmount > 0
? `Found transfer of ${transferAmount}, expected ${PRICE_USDC}`
: "No valid token transfer instruction found"
});
}
// Step 2: Simulate the transaction BEFORE submitting
console.log("Simulating transaction...");
try {
const simulation = await connection.simulateTransaction(tx);
if (simulation.value.err) {
console.error("Simulation failed:", simulation.value.err);
return res.status(402).json({
error: "Transaction simulation failed",
details: simulation.value.err,
logs: simulation.value.logs
});
}
console.log(" ✓ Simulation successful");
} catch (simError) {
console.error("Simulation error:", simError);
return res.status(402).json({
error: "Failed to simulate transaction",
details:
simError instanceof Error ? simError.message : "Unknown error"
});
}
// Step 3: Submit the transaction (only if verified and simulated successfully)
// Note: Solana blockchain automatically rejects duplicate transaction signatures
console.log("Submitting transaction to network...");
const signature = await connection.sendRawTransaction(txBuffer, {
skipPreflight: false,
preflightCommitment: "confirmed"
});
console.log(`Transaction submitted: ${signature}`);
// Wait for confirmation
const confirmation = await connection.confirmTransaction(
signature,
"confirmed"
);
if (confirmation.value.err) {
return res.status(402).json({
error: "Transaction failed onchain",
details: confirmation.value.err
});
}
// Fetch the transaction to verify payment details
const confirmedTx = await connection.getTransaction(signature, {
commitment: "confirmed",
maxSupportedTransactionVersion: 0
});
if (!confirmedTx) {
return res.status(402).json({
error: "Could not fetch confirmed transaction"
});
}
// Verify token balance changes from transaction metadata
const postTokenBalances = confirmedTx.meta?.postTokenBalances ?? [];
const preTokenBalances = confirmedTx.meta?.preTokenBalances ?? [];
// Find the recipient's token account in the balance changes
let amountReceived = 0;
for (let i = 0; i < postTokenBalances.length; i++) {
const postBal = postTokenBalances[i];
const preBal = preTokenBalances.find(
(pre) => pre.accountIndex === postBal.accountIndex
);
// Check if this is the recipient's account
const accountKey =
confirmedTx.transaction.message.staticAccountKeys[
postBal.accountIndex
];
if (accountKey && accountKey.equals(RECIPIENT_TOKEN_ACCOUNT)) {
const postAmount = postBal.uiTokenAmount.amount;
const preAmount = preBal?.uiTokenAmount.amount ?? "0";
amountReceived = Number(postAmount) - Number(preAmount);
break;
}
}
if (amountReceived < PRICE_USDC) {
return res.status(402).json({
error: `Insufficient payment: received ${amountReceived}, expected ${PRICE_USDC}`
});
}
console.log(
`Payment verified: ${amountReceived / 1000000} USDC received`
);
console.log(
`View transaction: https://explorer.solana.com/tx/${signature}?cluster=devnet`
);
// Payment verified! Return premium content
return res.json({
data: "Premium content - USDC payment verified!",
paymentDetails: {
signature,
amount: amountReceived,
amountUSDC: amountReceived / 1000000,
recipient: RECIPIENT_TOKEN_ACCOUNT.toBase58(),
explorerUrl: `https://explorer.solana.com/tx/${signature}?cluster=devnet`
}
});
} catch (e) {
console.error("Payment verification error:", e);
return res.status(402).json({
error: "Payment verification failed",
details: e instanceof Error ? e.message : "Unknown error"
});
}
}
// No payment provided - return 402 with payment details
console.log("New USDC payment quote requested");
return res.status(402).json({
payment: {
recipientWallet: RECIPIENT_WALLET.toBase58(),
tokenAccount: RECIPIENT_TOKEN_ACCOUNT.toBase58(),
mint: USDC_MINT.toBase58(),
amount: PRICE_USDC,
amountUSDC: PRICE_USDC / 1000000,
cluster: "devnet",
message: "Send USDC to the token account"
}
});
});
app.listen(3001, () => console.log("x402 USDC server listening on :3001"));

Мінімальний клієнт (Node)

import { Connection, Keypair, PublicKey, Transaction } from "@solana/web3.js";
import {
createTransferInstruction,
getOrCreateAssociatedTokenAccount,
createAssociatedTokenAccountInstruction,
getAccount
} from "@solana/spl-token";
import fetch from "node-fetch";
import { readFileSync } from "fs";
const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const keypairData = JSON.parse(
readFileSync("./pay-in-usdc/client.json", "utf-8")
);
const payer = Keypair.fromSecretKey(Uint8Array.from(keypairData));
async function run() {
// 1) Request payment quote from server
const quote = await fetch("http://localhost:3001/premium");
const q = (await quote.json()) as {
payment: {
tokenAccount: string;
mint: string;
amount: number;
amountUSDC: number;
cluster: string;
};
};
if (quote.status !== 402) throw new Error("Expected 402 quote");
const recipientTokenAccount = new PublicKey(q.payment.tokenAccount);
const mint = new PublicKey(q.payment.mint);
const amount = q.payment.amount;
console.log("USDC Payment required:");
console.log(` Recipient Token Account: ${q.payment.tokenAccount}`);
console.log(` Mint (USDC): ${q.payment.mint}`);
console.log(
` Amount: ${q.payment.amountUSDC} USDC (${amount} smallest units)`
);
// 2) Get or create the payer's associated token account
console.log("\nChecking/creating associated token account...");
const payerTokenAccount = await getOrCreateAssociatedTokenAccount(
connection,
payer,
mint,
payer.publicKey
);
console.log(` Payer Token Account: ${payerTokenAccount.address.toBase58()}`);
// Check if payer has enough USDC
const balance = await connection.getTokenAccountBalance(
payerTokenAccount.address
);
console.log(` Current Balance: ${balance.value.uiAmountString} USDC`);
if (Number(balance.value.amount) < amount) {
throw new Error(
`Insufficient USDC balance. Have: ${balance.value.uiAmountString}, Need: ${q.payment.amountUSDC}`
);
}
// 3) Check if recipient token account exists, create if not
console.log("\nChecking recipient token account...");
let recipientAccountExists = false;
try {
await getAccount(connection, recipientTokenAccount);
recipientAccountExists = true;
console.log(" ✓ Recipient token account exists");
} catch (error) {
console.log(" ⚠ Recipient token account doesn't exist, will create it");
}
// 4) Create USDC transfer transaction (but DON'T submit it)
const { blockhash } = await connection.getLatestBlockhash();
const tx = new Transaction({
feePayer: payer.publicKey,
blockhash,
lastValidBlockHeight: (await connection.getLatestBlockhash())
.lastValidBlockHeight
});
// Add create account instruction if needed
if (!recipientAccountExists) {
// We need to know the recipient wallet address to create the ATA
// The server should provide this, so let's get it from the wallet address
// Usually the server will already have the token account, but to be sure for the examples
// lets create one.
const recipientWallet = new PublicKey(
"seFkxFkXEY9JGEpCyPfCWTuPZG9WK6ucf95zvKCfsRX"
);
const createAccountIx = createAssociatedTokenAccountInstruction(
payer.publicKey, // payer
recipientTokenAccount, // associated token account address
recipientWallet, // owner
mint // mint
);
tx.add(createAccountIx);
console.log(" + Added create token account instruction");
}
// Add transfer instruction
const transferIx = createTransferInstruction(
payerTokenAccount.address, // source
recipientTokenAccount, // destination
payer.publicKey, // owner
amount // amount in smallest units
);
tx.add(transferIx);
// Sign the transaction (but don't send it, the server will do that)
tx.sign(payer);
// Serialize the signed transaction
const serializedTx = tx.serialize().toString("base64");
console.log("\nTransaction created and signed (not submitted yet)");
console.log(` Instructions: ${tx.instructions.length}`);
// 4) Send X-Payment header with serialized transaction (x402 standard)
const paymentProof = {
x402Version: 1,
scheme: "exact",
network:
q.payment.cluster === "devnet" ? "solana-devnet" : "solana-mainnet",
payload: {
serializedTransaction: serializedTx
}
};
// Base64 encode the payment proof
const xPaymentHeader = Buffer.from(JSON.stringify(paymentProof)).toString(
"base64"
);
console.log(
"\nSending payment proof to server (server will submit transaction)..."
);
const paid = await fetch("http://localhost:3001/premium", {
headers: {
"X-Payment": xPaymentHeader
}
});
const result = (await paid.json()) as {
data?: string;
error?: string;
paymentDetails?: {
signature: string;
amount: number;
amountUSDC: number;
recipient: string;
explorerUrl: string;
};
};
console.log("\nServer response:");
console.log(result);
// Display explorer link if payment was successful
if (result.paymentDetails?.explorerUrl) {
console.log("\n🔗 View transaction on Solana Explorer:");
console.log(result.paymentDetails.explorerUrl);
}
}
run().catch(console.error);

Покращення

  • Розгляньте можливість повернення JWT після оплати, щоб клієнти могли короткочасно повторно використовувати доступ. ACK значно спрощує це.
  • Переконайтеся, що ваші ключі не витікають, і зберігайте їх у змінних середовища.

Is this page helpful?