Payment Processing Examples

Real-world payment processing implementations using Omne blockchain. From simple transfers to complex e-commerce integrations with automatic handling.

E-commerce Integration

Online Store Checkout

Complete checkout flow with payment confirmation and order processing.

// Frontend - React Checkout Component import { useState } from 'react' import { OmneClient, Account } from '@omne/sdk' interface CheckoutProps { orderTotal: string merchantAddress: string orderId: string } export function Checkout({ orderTotal, merchantAddress, orderId }: CheckoutProps) { const [paymentStatus, setPaymentStatus] = useState<'pending' | 'processing' | 'completed' | 'failed'>('pending') const [txHash, setTxHash] = useState<string>('') const processPayment = async () => { try { setPaymentStatus('processing') // Connect to user's wallet const client = new OmneClient({ network: 'mainnet' }) const account = await client.connectWallet() // Create payment transaction const payment = await client.transfer({ from: account.address, to: merchantAddress, amount: orderTotal, memo: `Order #${orderId}`, confirmations: 3 // Wait for 3 confirmations }) setTxHash(payment.hash) // Notify backend await fetch('/api/payments/confirm', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orderId, txHash: payment.hash, amount: orderTotal, customerAddress: account.address }) }) setPaymentStatus('completed') } catch (error) { console.error('Payment failed:', error) setPaymentStatus('failed') } } return ( <div className="checkout-container"> <div className="order-summary"> <h3>Order Total: {orderTotal} OMNE</h3> <p>Order ID: {orderId}</p> </div> <button onClick={processPayment} disabled={paymentStatus === 'processing'} className="pay-button" > {paymentStatus === 'processing' ? 'Processing...' : 'Pay with OMNE'} </button> {txHash && ( <div className="payment-confirmation"> <p>Payment Transaction: {txHash}</p> <a href={`https://explorer.omne.foundation/tx/${txHash}`}> View on Explorer </a> </div> )} </div> ) }

Backend Payment Verification

Server-side payment verification and order fulfillment.

// Backend - Node.js Payment Verification import express from 'express' import { OmneClient } from '@omne/sdk' const app = express() const client = new OmneClient({ network: 'mainnet' }) // Payment confirmation endpoint app.post('/api/payments/confirm', async (req, res) => { try { const { orderId, txHash, amount, customerAddress } = req.body // Verify transaction on blockchain const transaction = await client.getTransaction(txHash) // Validate transaction details if (!transaction || transaction.status !== 'success') { return res.status(400).json({ error: 'Invalid transaction' }) } if (transaction.amount !== amount) { return res.status(400).json({ error: 'Amount mismatch' }) } if (transaction.to !== process.env.MERCHANT_ADDRESS) { return res.status(400).json({ error: 'Invalid recipient' }) } // Wait for sufficient confirmations if (transaction.confirmations < 3) { return res.status(202).json({ status: 'pending', confirmations: transaction.confirmations }) } // Update order in database await updateOrderStatus(orderId, { status: 'paid', txHash, paidAmount: amount, paidAt: new Date(), customerAddress }) // Trigger order fulfillment await fulfillOrder(orderId) // Send confirmation email await sendPaymentConfirmation(orderId, customerAddress, txHash) res.json({ status: 'confirmed', orderId, txHash }) } catch (error) { console.error('Payment verification failed:', error) res.status(500).json({ error: 'Payment verification failed' }) } }) // Webhook for real-time transaction updates app.post('/api/webhooks/transaction', async (req, res) => { const { txHash, status, confirmations } = req.body // Find order by transaction hash const order = await findOrderByTxHash(txHash) if (!order) { return res.status(404).json({ error: 'Order not found' }) } // Update order status based on confirmations if (confirmations >= 3 && status === 'success') { await updateOrderStatus(order.id, { status: 'confirmed' }) await fulfillOrder(order.id) } res.json({ status: 'processed' }) }) async function fulfillOrder(orderId: string) { // Implement order fulfillment logic // - Update inventory // - Generate shipping labels // - Send confirmation emails // - Trigger delivery process } app.listen(3001, () => { console.log('Payment server running on port 3001') })

Subscription Payments

Monthly Subscription Handler

Automated recurring payments with smart contract escrow.

// Subscription Management Smart Contract import { SmartContract, Account, OmneClient } from '@omne/sdk' class SubscriptionManager { private contract: SmartContract private client: OmneClient constructor(contractAddress: string) { this.client = new OmneClient({ network: 'mainnet' }) this.contract = new SmartContract(contractAddress, subscriptionABI) } // Create new subscription async createSubscription( account: Account, serviceProvider: string, amount: string, intervalDays: number ) { const tx = await this.contract.execute(account, 'createSubscription', { provider: serviceProvider, amount: amount, interval: intervalDays * 24 * 60 * 60, // Convert to seconds startTime: Math.floor(Date.now() / 1000) }) return await this.client.waitForTransaction(tx.hash) } // Process subscription payment async processPayment(subscriptionId: string, account: Account) { try { // Check if payment is due const subscription = await this.contract.call('getSubscription', [subscriptionId]) const now = Math.floor(Date.now() / 1000) if (now < subscription.nextPaymentDue) { throw new Error('Payment not yet due') } // Execute payment const tx = await this.contract.execute(account, 'processPayment', { subscriptionId, amount: subscription.amount }) // Update next payment date await this.contract.execute(account, 'updateNextPayment', { subscriptionId, nextPayment: now + subscription.interval }) return tx } catch (error) { console.error('Subscription payment failed:', error) throw error } } // Cancel subscription async cancelSubscription(subscriptionId: string, account: Account) { return await this.contract.execute(account, 'cancelSubscription', { subscriptionId }) } // Get subscription status async getSubscriptionStatus(subscriptionId: string) { const subscription = await this.contract.call('getSubscription', [subscriptionId]) const now = Math.floor(Date.now() / 1000) return { id: subscriptionId, isActive: subscription.isActive, amount: subscription.amount, nextPaymentDue: subscription.nextPaymentDue, isPastDue: now > subscription.nextPaymentDue, provider: subscription.provider, subscriber: subscription.subscriber } } } // Usage example const subscriptionManager = new SubscriptionManager('omne1contract...') // Create monthly subscription for $99 await subscriptionManager.createSubscription( userAccount, 'omne1service-provider...', '99000000', // 99 OMNE 30 // 30 days )

Automated Payment Processing

Background service for processing recurring payments automatically.

import asyncio import schedule import time from datetime import datetime, timedelta from omne_sdk import OmneClient, Account class SubscriptionProcessor: def __init__(self, contract_address: str, processor_account: Account): self.client = OmneClient(network='mainnet') self.contract_address = contract_address self.processor_account = processor_account async def process_due_subscriptions(self): """Process all subscriptions that are due for payment""" try: # Get all active subscriptions subscriptions = await self.get_active_subscriptions() due_subscriptions = [ sub for sub in subscriptions if self.is_payment_due(sub) ] print(f"Processing {len(due_subscriptions)} due subscriptions") # Process payments concurrently tasks = [ self.process_subscription_payment(sub) for sub in due_subscriptions ] results = await asyncio.gather(*tasks, return_exceptions=True) # Log results successful = sum(1 for r in results if not isinstance(r, Exception)) failed = len(results) - successful print(f"Processed: {successful} successful, {failed} failed") except Exception as e: print(f"Error processing subscriptions: {e}") async def process_subscription_payment(self, subscription): """Process individual subscription payment""" try: subscription_id = subscription['id'] amount = subscription['amount'] subscriber = subscription['subscriber'] # Check subscriber balance balance = await self.client.get_balance(subscriber) if int(balance.amount) < int(amount): await self.handle_insufficient_funds(subscription) return # Execute payment tx = await self.client.contract_execute( self.contract_address, 'processSubscriptionPayment', { 'subscription_id': subscription_id, 'processor': self.processor_account.address }, account=self.processor_account ) print(f"Processed subscription {subscription_id}: {tx.hash}") # Send confirmation await self.send_payment_confirmation(subscription, tx.hash) except Exception as e: print(f"Failed to process subscription {subscription['id']}: {e}") await self.handle_payment_failure(subscription, str(e)) async def handle_insufficient_funds(self, subscription): """Handle cases where subscriber has insufficient funds""" subscription_id = subscription['id'] # Mark subscription as past due await self.client.contract_execute( self.contract_address, 'markPastDue', {'subscription_id': subscription_id}, account=self.processor_account ) # Send notification to subscriber await self.send_insufficient_funds_notification(subscription) # Schedule retry in 24 hours retry_time = datetime.now() + timedelta(hours=24) await self.schedule_retry(subscription_id, retry_time) def is_payment_due(self, subscription) -> bool: """Check if payment is due for subscription""" now = int(time.time()) next_payment = subscription['next_payment_due'] return now >= next_payment async def get_active_subscriptions(self): """Retrieve all active subscriptions from contract""" return await self.client.contract_call( self.contract_address, 'getActiveSubscriptions', [] ) def start_processing(self): """Start the subscription processing scheduler""" # Process subscriptions every hour schedule.every().hour.do( lambda: asyncio.run(self.process_due_subscriptions()) ) print("Subscription processor started") while True: schedule.run_pending() time.sleep(60) # Check every minute # Start the processor processor_account = Account.from_private_key(os.getenv('PROCESSOR_PRIVATE_KEY')) processor = SubscriptionProcessor('omne1subscription-contract...', processor_account) processor.start_processing()

Escrow Payments

Marketplace Escrow

Secure escrow system for marketplace transactions with dispute resolution.

// Escrow Smart Contract Integration import { SmartContract, Account } from '@omne/sdk' class EscrowService { private contract: SmartContract constructor(contractAddress: string) { this.contract = new SmartContract(contractAddress, escrowABI) } // Create escrow for marketplace transaction async createEscrow( buyer: Account, sellerAddress: string, arbitratorAddress: string, amount: string, description: string, timeoutDays: number = 30 ) { const escrowId = `escrow_${Date.now()}_${Math.random().toString(36).substr(2, 9)}` const tx = await this.contract.execute(buyer, 'createEscrow', { escrowId, buyer: buyer.address, seller: sellerAddress, arbitrator: arbitratorAddress, amount, description, timeout: timeoutDays * 24 * 60 * 60, // Convert to seconds createdAt: Math.floor(Date.now() / 1000) }, { // Send funds to escrow contract amount: amount, denom: 'uomne' }) return { escrowId, txHash: tx.hash } } // Seller confirms delivery/completion async confirmDelivery(seller: Account, escrowId: string) { return await this.contract.execute(seller, 'confirmDelivery', { escrowId, confirmedBy: seller.address, confirmedAt: Math.floor(Date.now() / 1000) }) } // Buyer releases funds to seller async releaseFunds(buyer: Account, escrowId: string, rating?: number) { const params: any = { escrowId, releasedBy: buyer.address, releasedAt: Math.floor(Date.now() / 1000) } if (rating !== undefined) { params.buyerRating = rating } return await this.contract.execute(buyer, 'releaseFunds', params) } // Initiate dispute (by buyer or seller) async initiateDispute( account: Account, escrowId: string, reason: string, evidence: string[] ) { return await this.contract.execute(account, 'initiateDispute', { escrowId, disputeReason: reason, evidence: evidence, disputedBy: account.address, disputedAt: Math.floor(Date.now() / 1000) }) } // Arbitrator resolves dispute async resolveDispute( arbitrator: Account, escrowId: string, resolution: 'release_to_seller' | 'refund_to_buyer' | 'partial_split', buyerAmount?: string, sellerAmount?: string, reasoning?: string ) { const params: any = { escrowId, resolution, resolvedBy: arbitrator.address, resolvedAt: Math.floor(Date.now() / 1000) } if (resolution === 'partial_split') { params.buyerAmount = buyerAmount params.sellerAmount = sellerAmount } if (reasoning) { params.reasoning = reasoning } return await this.contract.execute(arbitrator, 'resolveDispute', params) } // Get escrow details async getEscrowDetails(escrowId: string) { const escrow = await this.contract.call('getEscrow', [escrowId]) return { id: escrowId, buyer: escrow.buyer, seller: escrow.seller, arbitrator: escrow.arbitrator, amount: escrow.amount, description: escrow.description, status: escrow.status, // 'created', 'delivered', 'completed', 'disputed', 'resolved' createdAt: new Date(escrow.createdAt * 1000), deliveredAt: escrow.deliveredAt ? new Date(escrow.deliveredAt * 1000) : null, completedAt: escrow.completedAt ? new Date(escrow.completedAt * 1000) : null, disputeReason: escrow.disputeReason, resolution: escrow.resolution } } // Auto-release after timeout (if no disputes) async checkTimeouts() { const activeEscrows = await this.contract.call('getActiveEscrows', []) const now = Math.floor(Date.now() / 1000) for (const escrow of activeEscrows) { if (escrow.status === 'delivered' && now > escrow.deliveredAt + escrow.timeout && !escrow.hasDispute) { // Auto-release to seller after timeout await this.contract.execute(null, 'autoRelease', { escrowId: escrow.id }) } } } } // Usage example - Marketplace transaction const escrowService = new EscrowService('omne1escrow-contract...') // Buyer creates escrow for purchase const { escrowId } = await escrowService.createEscrow( buyerAccount, 'omne1seller-address...', 'omne1arbitrator-address...', '50000000', // 50 OMNE 'Digital artwork purchase', 7 // 7 days timeout ) // Seller confirms delivery await escrowService.confirmDelivery(sellerAccount, escrowId) // Buyer releases funds after receiving item await escrowService.releaseFunds(buyerAccount, escrowId, 5) // 5-star rating

Payment Streaming

Salary Streaming

Real-time salary streaming for continuous payment distribution.

package main import ( "context" "time" "math/big" "github.com/omne-foundation/omne-go-sdk/client" "github.com/omne-foundation/omne-go-sdk/contracts" ) type SalaryStream struct { ID string Employer string Employee string TotalAmount *big.Int StartTime time.Time EndTime time.Time WithdrawnAmount *big.Int IsActive bool } type StreamingPayroll struct { client *client.OmneClient contract *contracts.Contract } func NewStreamingPayroll(contractAddr string) (*StreamingPayroll, error) { client, err := client.NewOmneClient(&client.Config{Network: "mainnet"}) if err != nil { return nil, err } contract, err := contracts.NewContract(contractAddr, streamingABI) if err != nil { return nil, err } return &StreamingPayroll{ client: client, contract: contract, }, nil } // Create salary stream func (sp *StreamingPayroll) CreateSalaryStream( ctx context.Context, employer *account.Account, employeeAddr string, monthlySalary *big.Int, startDate time.Time, durationMonths int, ) (*SalaryStream, error) { streamID := fmt.Sprintf("salary_%d_%s", time.Now().Unix(), employeeAddr[0:8]) endDate := startDate.AddDate(0, durationMonths, 0) totalAmount := new(big.Int).Mul(monthlySalary, big.NewInt(int64(durationMonths))) // Create stream on contract result, err := sp.contract.Execute(ctx, employer, "createStream", []interface{}{ streamID, employeeAddr, totalAmount.String(), startDate.Unix(), endDate.Unix(), }, &contracts.ExecuteOptions{ Amount: totalAmount.String(), Denom: "uomne", }) if err != nil { return nil, fmt.Errorf("failed to create stream: %w", err) } return &SalaryStream{ ID: streamID, Employer: employer.Address(), Employee: employeeAddr, TotalAmount: totalAmount, StartTime: startDate, EndTime: endDate, WithdrawnAmount: big.NewInt(0), IsActive: true, }, nil } // Calculate available amount for withdrawal func (sp *StreamingPayroll) GetAvailableAmount( ctx context.Context, streamID string, ) (*big.Int, error) { stream, err := sp.getStreamDetails(ctx, streamID) if err != nil { return nil, err } now := time.Now() if now.Before(stream.StartTime) { return big.NewInt(0), nil } var streamedAmount *big.Int if now.After(stream.EndTime) { streamedAmount = stream.TotalAmount } else { // Calculate pro-rata amount based on time elapsed totalDuration := stream.EndTime.Sub(stream.StartTime) elapsedDuration := now.Sub(stream.StartTime) elapsedRatio := float64(elapsedDuration) / float64(totalDuration) streamedFloat := new(big.Float).Mul( new(big.Float).SetInt(stream.TotalAmount), big.NewFloat(elapsedRatio), ) streamedAmount, _ = streamedFloat.Int(nil) } // Available = Streamed - Already Withdrawn available := new(big.Int).Sub(streamedAmount, stream.WithdrawnAmount) return available, nil } // Employee withdraws available salary func (sp *StreamingPayroll) WithdrawSalary( ctx context.Context, employee *account.Account, streamID string, amount *big.Int, ) error { // Check available amount available, err := sp.GetAvailableAmount(ctx, streamID) if err != nil { return err } if amount.Cmp(available) > 0 { return fmt.Errorf("insufficient available amount: have %s, want %s", available.String(), amount.String()) } // Execute withdrawal _, err = sp.contract.Execute(ctx, employee, "withdraw", []interface{}{ streamID, amount.String(), }) if err != nil { return fmt.Errorf("withdrawal failed: %w", err) } return nil } // Get stream details func (sp *StreamingPayroll) getStreamDetails( ctx context.Context, streamID string, ) (*SalaryStream, error) { result, err := sp.contract.Call(ctx, "getStream", []interface{}{streamID}) if err != nil { return nil, err } streamData := result.(map[string]interface{}) totalAmount, _ := new(big.Int).SetString(streamData["totalAmount"].(string), 10) withdrawnAmount, _ := new(big.Int).SetString(streamData["withdrawnAmount"].(string), 10) return &SalaryStream{ ID: streamID, Employer: streamData["employer"].(string), Employee: streamData["employee"].(string), TotalAmount: totalAmount, StartTime: time.Unix(streamData["startTime"].(int64), 0), EndTime: time.Unix(streamData["endTime"].(int64), 0), WithdrawnAmount: withdrawnAmount, IsActive: streamData["isActive"].(bool), }, nil } // Monitor stream and auto-notify employee func (sp *StreamingPayroll) MonitorStream(ctx context.Context, streamID string) { ticker := time.NewTicker(24 * time.Hour) // Check daily defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: available, err := sp.GetAvailableAmount(ctx, streamID) if err != nil { continue } // Notify employee if significant amount available minWithdrawal := big.NewInt(1000000) // 1 OMNE if available.Cmp(minWithdrawal) >= 0 { sp.notifyEmployee(streamID, available) } } } } func (sp *StreamingPayroll) notifyEmployee(streamID string, amount *big.Int) { // Implementation: Send email/SMS/push notification fmt.Printf("Employee has %s OMNE available for withdrawal from stream %s ", amount.String(), streamID) } // Usage example func main() { payroll, _ := NewStreamingPayroll("omne1streaming-contract...") // Create 6-month salary stream for $5000/month monthlySalary := big.NewInt(5000 * 1000000) // 5000 OMNE stream, _ := payroll.CreateSalaryStream( context.Background(), employerAccount, "omne1employee...", monthlySalary, time.Now(), 6, // 6 months ) // Employee can withdraw available amount anytime available, _ := payroll.GetAvailableAmount(context.Background(), stream.ID) payroll.WithdrawSalary(context.Background(), employeeAccount, stream.ID, available) }

Next Steps

Production Deployment

Deploy your payment system to mainnet with monitoring and security.

Deployment Guide →

Smart Contracts

Build custom payment logic with Omne smart contracts.

Contract docs →

Integration Support

Get help integrating payments into your existing systems.

Contact support →