═══════════════════════════════════════════════════════════════════════════════ ARCADIA GAME SDK - DEVELOPER DOCUMENTATION ═══════════════════════════════════════════════════════════════════════════════ Document: Payments Generated: 2/13/2026, 7:49:24 PM Version: 1.0.0 ═══════════════════════════════════════════════════════════════════════════════ Payments Guide ══════════════════════════════════════════════════════════════════════ This guide covers implementing pay-to-play and in-game purchases using the Arcadia Game SDK. Overview ════════════════════════════════════════════════════════════ The Arcadia Game SDK handles all payment complexity for you. You simply request a payment with an amount and token type, and the SDK: 1. Prompts the player to approve the transaction 2. Sends the transaction to the blockchain 3. Returns complete payment details immediately 4. Handles fee calculation and developer payouts automatically Payment Types ════════════════════════════════════════════════════════════ Pay-to-Play ══════════════════════════════════════════════════ One-time payment required to access or start a game. Typically used for: • Game access fees • Premium game modes • One-time unlocks In-Game Purchases ══════════════════════════════════════════════════ Purchases made during gameplay. Typically used for: • Items and equipment • Upgrades and power-ups • Cosmetics and skins • Currency packs Payment Flow ════════════════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [MERMAID] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ sequenceDiagram participant Game participant SDK participant Arcadia participant Wallet participant Blockchain Game->>SDK: payment.payToPlay(amount, token) SDK->>Arcadia: Payment request via postMessage Arcadia->>Wallet: Request transaction approval Wallet->>Blockchain: Send transaction Blockchain-->>Wallet: Transaction signature Wallet-->>Arcadia: Transaction confirmed Arcadia->>SDK: Payment result with details SDK-->>Game: PaymentResult object ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Pay-to-Play Implementation ════════════════════════════════════════════════════════════ Basic Example ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { ArcadiaSDK, PaymentFailedError } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Payment successful! console.log('Payment successful!'); console.log('Transaction:', result.txSignature); console.log('Amount:', result.amount, result.token); console.log('Timestamp:', result.timestamp); // Start game startGame(); } catch (error) { if (error instanceof PaymentFailedError) { console.error('Payment failed:', error.message); showError('Payment failed. Please try again.'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ With Payment Verification ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function handlePayToPlay(requiredAmount: number) { try { const result = await arcadia.payment.payToPlay(requiredAmount, 'SOL'); // Verify payment details if (result.success && result.amount === requiredAmount && result.token === 'SOL') { // Payment verified - proceed await markPlayerAsPaid(walletAddress); await logPayment(result); startGame(); } else { throw new Error('Payment verification failed'); } } catch (error) { handlePaymentError(error); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Complete Pay-to-Play Flow ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class GamePaymentManager { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; constructor(arcadia: ArcadiaSDK) { this.arcadia = arcadia; } async checkPaymentRequired(): Promise { if (!this.walletAddress) { this.walletAddress = await this.arcadia.getWalletAddress(); } // Check if player has already paid const playerData = await this.loadPlayerData(this.walletAddress!); return !playerData.hasPaid; } async processPayToPlay(amount: number, token: 'SOL' | 'USDC'): Promise { try { const result = await this.arcadia.payment.payToPlay(amount, token); // Verify payment if (!result.success || result.amount !== amount) { throw new Error('Payment verification failed'); } // Update player data await this.markAsPaid(this.walletAddress!, result); // Log payment for analytics await this.logPayment(result); return true; } catch (error) { console.error('Payment error:', error); return false; } } private async markAsPaid(walletAddress: string, paymentResult: PaymentResult) { const playerData = await this.loadPlayerData(walletAddress); playerData.hasPaid = true; playerData.paymentTx = paymentResult.txSignature; playerData.paidAt = paymentResult.timestamp; await this.savePlayerData(walletAddress, playerData); } private async logPayment(result: PaymentResult) { // Log to your analytics service await fetch('/api/analytics/payment', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ type: 'pay_to_play', ...result, }), }); } private async loadPlayerData(walletAddress: string) { // Load player data const response = await fetch([/api/player-data?wallet=${walletAddress}]); return response.json(); } private async savePlayerData(walletAddress: string, data: any) { // Save player data await fetch('/api/player-data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ walletAddress, data }), }); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ In-Game Purchases ════════════════════════════════════════════════════════════ Basic Example ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function purchaseItem(itemId: string, price: number) { try { const result = await arcadia.payment.purchaseItem(itemId, price, 'SOL'); // Verify purchase if (result.success && result.amount === price) { // Add item to inventory addItemToInventory(itemId); // Update player data await savePurchase(walletAddress, { itemId, ...result, }); showSuccess('Item purchased successfully!'); } } catch (error) { console.error('Purchase failed:', error); showError('Purchase failed. Please try again.'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Item Shop Implementation ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ class ItemShop { private arcadia: ArcadiaSDK; private walletAddress: string | null = null; constructor(arcadia: ArcadiaSDK) { this.arcadia = arcadia; } async buyItem(item: ShopItem) { if (!this.walletAddress) { this.walletAddress = await this.arcadia.getWalletAddress(); if (!this.walletAddress) { showError('Please connect your wallet'); return; } } try { // Show loading state showLoading([Purchasing ${item.name}...]); // Process purchase const result = await this.arcadia.payment.purchaseItem( item.id, item.price, item.token ); // Verify purchase if (result.success && result.amount === item.price && result.token === item.token) { // Add item to inventory await this.addToInventory(this.walletAddress, item.id); // Update player balance await this.updatePlayerBalance(this.walletAddress, -item.price); // Log purchase await this.logPurchase(item, result); showSuccess([${item.name} purchased successfully!]); } else { throw new Error('Purchase verification failed'); } } catch (error) { console.error('Purchase error:', error); showError('Purchase failed: ' + error.message); } finally { hideLoading(); } } private async addToInventory(walletAddress: string, itemId: string) { const playerData = await this.loadPlayerData(walletAddress); if (!playerData.inventory) { playerData.inventory = []; } playerData.inventory.push(itemId); await this.savePlayerData(walletAddress, playerData); } private async updatePlayerBalance(walletAddress: string, amount: number) { // Update player's in-game balance const playerData = await this.loadPlayerData(walletAddress); playerData.balance = (playerData.balance || 0) + amount; await this.savePlayerData(walletAddress, playerData); } private async logPurchase(item: ShopItem, result: PaymentResult) { await fetch('/api/analytics/purchase', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ itemId: item.id, itemName: item.name, ...result, }), }); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Payment Result Structure ════════════════════════════════════════════════════════════ The [PaymentResult] object contains all payment details: ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ interface PaymentResult { success: boolean; // Whether payment was successful txSignature: string; // Blockchain transaction signature amount: number; // Amount paid by user token: 'SOL' | 'USDC'; // Token type used timestamp: string; // ISO timestamp when payment completed purchaseId?: string; // Arcadia purchase ID (for tracking) platformFee?: number; // Platform fee deducted developerAmount?: number; // Amount received by developer (after fees) error?: string; // Error message if payment failed } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Using Payment Details ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ const result = await arcadia.payment.payToPlay(0.5, 'SOL'); // Store in your database await savePaymentRecord({ walletAddress: walletAddress, txSignature: result.txSignature, amount: result.amount, token: result.token, timestamp: result.timestamp, purchaseId: result.purchaseId, platformFee: result.platformFee, developerAmount: result.developerAmount, }); // Use for analytics trackEvent('payment_completed', { amount: result.amount, token: result.token, platformFee: result.platformFee, }); ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Error Handling ════════════════════════════════════════════════════════════ Common Payment Errors ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ import { PaymentFailedError, WalletNotConnectedError, InvalidAmountError, InvalidTokenError, TimeoutError, } from '@arcadiasol/sdk'; try { const result = await arcadia.payment.payToPlay(0.5, 'SOL'); } catch (error) { if (error instanceof WalletNotConnectedError) { showError('Please connect your wallet to make a payment'); } else if (error instanceof PaymentFailedError) { showError('Payment failed: ' + error.message); // Check error.txSignature if available } else if (error instanceof InvalidAmountError) { showError('Invalid payment amount'); } else if (error instanceof InvalidTokenError) { showError('Invalid token type. Use SOL or USDC'); } else if (error instanceof TimeoutError) { showError('Payment request timed out. Please try again.'); } else { showError('An unexpected error occurred'); } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Retry Logic ══════════════════════════════════════════════════ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ CODE BLOCK [TYPESCRIPT] ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ async function payToPlayWithRetry(amount: number, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const result = await arcadia.payment.payToPlay(amount, 'SOL'); return result; } catch (error) { if (i === maxRetries - 1) { throw error; // Last attempt failed } // Wait before retry await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Best Practices ════════════════════════════════════════════════════════════ 1. Verify Payment Amount - Always verify the returned amount matches what you requested 2. Store Transaction Signatures - Keep transaction signatures for record-keeping 3. Handle Errors Gracefully - Provide clear error messages to users 4. Show Loading States - Indicate when payment is processing 5. Don't Block on Payment - Payments return immediately after transaction is sent 6. Log All Payments - Keep records for analytics and debugging 7. Validate Before Processing - Check payment details before granting items/access Payment Timing ════════════════════════════════════════════════════════════ Payments return immediately after the transaction is sent to the blockchain. The SDK doesn't wait for full confirmation, making the payment experience instant for players. However, you should: • Trust the payment result for immediate game actions • Use transaction signatures for verification if needed • Handle edge cases where transactions might fail after initial success Next Steps ════════════════════════════════════════════════════════════ • Review API Reference for complete payment method documentation • Check Examples for complete payment implementations • Read Error Handling for detailed error information ═══════════════════════════════════════════════════════════════════════════════ For the latest documentation, visit: https://arcadia.obeliskprotocol.io/developer For support, email: support@arcadia.com ═══════════════════════════════════════════════════════════════════════════════