Що таке 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
Примітка: Фасилітатор є повністю необов'язковим, і ви також можете реалізувати власну логіку перевірки за допомогою кількох рядків коду. Фасилітатор абстрагує деталі інтеграції з блокчейном від сервера та клієнта, що спрощує реалізацію.
Ключові елементи специфікації: структура 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 з підтримкою Solana | payai.network |
| Coinbase | Так / Python у розробці | Референсна реалізація протоколу x402 від Coinbase | GitHub |
| ACK | У PR | Протокол агентних платежів із підтримкою x402 | GitHub |
| Crossmint | У розробці | Платежі, гаманці; агентні фінанси; не специфічно для x402 | crossmint.com |
| A2A x402 (Google) | У розробці | Платежі між агентами з використанням Google AI | GitHub |
| 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 fileconst 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 interfaceconst wallet = {network,publicKey: keypair.publicKey,updateTransaction: async (tx: VersionedTransaction) => {tx.sign([keypair]);return tx;}};// Setup payment handlerconst handler = createPaymentHandler(wallet, usdcMint, connection);const fetchWithPayer = wrap(fetch, { handlers: [handler] });// Call the API - payment happens automaticallyconst 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 confirmationapp.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 paymentapp.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
Є 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-examplesnpm install# Terminal 1: Start servernpm run usdc:server# Terminal 2: Run client (requires devnet USDC)npm run usdc:client
Огляд потоку
- Клієнт надсилає запит до
/premium. - Сервер відповідає 402 з умовами оплати: одержувач, сума.
- Клієнт створює транзакцію з інструкцією переказу одержувачу.
- Клієнт повторює запит до
/premiumз payload транзакції. - Сервер перевіряє транзакцію та відправляє її до мережі.
- Після підтвердження сервер відповідає 200.
Альтернатива для Solana: У Solana можна реалізувати варіант, де клієнт надсилає транзакцію безпосередньо в мережу з інструкцією memo (замість того, щоб надсилати її на сервер), а потім передає лише підпис транзакції на сервер для перевірки. Це вирішує проблему розриву з'єднання — якщо клієнт відключається після оплати, але до отримання контенту, він може повторити запит із тим самим підписом, оскільки платіж уже підтверджено в блокчейні. Однак цей підхід відхиляється від стандартного потоку x402.org (який передбачає, що сервер транслює транзакцію), тому в цьому прикладі ми використовуємо стандартний підхід.
Примітка: Код цього прикладу не пройшов аудит, не готовий до використання у виробничому середовищі та призначений лише для демонстраційних цілей. Він показує, що x402 можна реалізувати без залежностей і без використання фасилітатора. Використання фасилітатора зручне тим, що він приховує складність і може взяти на себе комісію за транзакції, але він також може бути єдиною точкою відмови — наприклад, коли на гаманці фасилітатора закінчуються кошти. Приклад сервера надсилає транзакції, підписані клієнтом. Можливо, вам знадобиться їх перевірити.
Мінімальний сервер (Express)
// x402-compliant server with USDC (SPL Token) paymentsimport 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 addressconst 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 priceconst PRICE_USDC = 100; // 0.0001 USDCconst app = express();app.use(express.json());// x402 endpoint - Quote or verify paymentapp.get("/premium", async (req, res) => {const xPaymentHeader = req.header("X-Payment");// If client provided X-Payment header, verify and submit transactionif (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 transactionconst 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 instructionconst instructions = tx.instructions;let validTransfer = false;let transferAmount = 0;for (const ix of instructions) {// Check if this is a Token Program instructionif (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 submittingconsole.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 signaturesconsole.log("Submitting transaction to network...");const signature = await connection.sendRawTransaction(txBuffer, {skipPreflight: false,preflightCommitment: "confirmed"});console.log(`Transaction submitted: ${signature}`);// Wait for confirmationconst 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 detailsconst 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 metadataconst postTokenBalances = confirmedTx.meta?.postTokenBalances ?? [];const preTokenBalances = confirmedTx.meta?.preTokenBalances ?? [];// Find the recipient's token account in the balance changeslet 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 accountconst 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 contentreturn 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 detailsconsole.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 serverconst 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 accountconsole.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 USDCconst 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 notconsole.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 neededif (!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, // payerrecipientTokenAccount, // associated token account addressrecipientWallet, // ownermint // mint);tx.add(createAccountIx);console.log(" + Added create token account instruction");}// Add transfer instructionconst transferIx = createTransferInstruction(payerTokenAccount.address, // sourcerecipientTokenAccount, // destinationpayer.publicKey, // owneramount // 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 transactionconst 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 proofconst 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 successfulif (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?