Deploying DePay
DePay is a decentralized payment gateway that enables businesses and developers to accept cryptocurrency payments directly into their wallets without intermediaries. Unlike traditional payment processors that hold custody of funds and charge significant fees, DePay provides a peer-to-peer payment infrastructure where transactions flow directly from customers to merchants on various blockchain networks. The platform supports multiple cryptocurrencies across Ethereum, Binance Smart Chain, Polygon, Solana, and other major blockchains, with automatic token swapping to ensure customers can pay with their preferred tokens while merchants receive their desired currency.
What makes DePay powerful is its focus on decentralization and user sovereignty. Merchants maintain complete control over their funds since payments go directly to their wallet addresses, eliminating counterparty risk and reducing transaction fees to minimal blockchain gas costs. The platform provides embeddable payment widgets, REST APIs for integration, and comprehensive SDKs for web and mobile applications. Whether you’re building an e-commerce platform, subscription service, donation system, or any application requiring crypto payments, DePay offers the infrastructure to accept digital assets while maintaining the principles of decentralization and self-custody.
Why Deploy DePay on Klutch.sh?
Deploying DePay on Klutch.sh offers several advantages for hosting your payment gateway infrastructure:
- Automatic Docker Detection: Klutch.sh recognizes your Dockerfile and handles containerization without manual configuration
- Persistent Storage: Built-in volume management ensures your configuration, transaction logs, and webhook data persist across deployments
- HTTPS by Default: Secure payment processing with automatic SSL certificates for API endpoints
- Database Support: Easy integration with PostgreSQL or MongoDB for transaction tracking and analytics
- Environment Management: Securely configure blockchain RPC endpoints, API keys, and webhook secrets through environment variables
- High Availability: Ensure payment infrastructure is always accessible for processing transactions
- Scalability: Handle increasing payment volumes as your business grows
Prerequisites
Before deploying DePay to Klutch.sh, ensure you have:
- A Klutch.sh account (sign up here)
- A GitHub account with a repository for your DePay deployment
- Basic understanding of Docker and containerization
- Cryptocurrency wallet addresses for receiving payments
- Blockchain RPC endpoints (Infura, Alchemy, or QuickNode)
- Basic knowledge of blockchain networks and smart contracts
- Git installed on your local development machine
- Understanding of REST APIs and webhooks
Understanding DePay Architecture
DePay follows a decentralized architecture designed for secure cryptocurrency payment processing:
Core Components
Payment Gateway Server
The DePay server is built with Node.js and Express, providing REST APIs for creating payment requests, tracking transactions, and managing webhooks. The server acts as a coordination layer between your application and blockchain networks, monitoring payment status, verifying transactions, and triggering callbacks when payments complete. It doesn’t process or custody funds but rather orchestrates the payment flow and provides confirmation once blockchain transactions are verified.
Blockchain Integration Layer
DePay connects to multiple blockchain networks through RPC endpoints:
- Ethereum: Native ETH and ERC-20 token payments
- Binance Smart Chain: BNB and BEP-20 tokens
- Polygon: MATIC and polygon-based tokens
- Solana: SOL and SPL tokens
- Arbitrum, Optimism, Avalanche: Layer 2 and alternative networks
The integration layer uses Web3.js and Ethers.js libraries to:
- Monitor wallet addresses for incoming transactions
- Verify transaction confirmations on-chain
- Calculate token values and conversion rates
- Handle token swap routing for payment flexibility
- Validate smart contract interactions
Payment Widget System
DePay provides embeddable JavaScript widgets that integrate into web applications:
- Responsive payment interface
- QR code generation for mobile wallets
- Real-time transaction status updates
- Multi-token selection with automatic conversion
- MetaMask, WalletConnect, and other wallet integrations
- Customizable branding and styling
The widget communicates with the backend server to create payment sessions and monitor completion.
Token Swap Router
One of DePay’s unique features is automatic token swapping. If a customer wants to pay with USDT but you prefer to receive USDC, DePay routes the payment through decentralized exchanges (Uniswap, PancakeSwap, etc.) to perform the conversion atomically within the same transaction. This provides:
- Payment flexibility for customers
- Merchant preference satisfaction
- Best price routing across DEXes
- Slippage protection
- Failed transaction rollback
Database and Transaction Tracking
Payment data is stored in a database (PostgreSQL or MongoDB):
- Payment requests with amounts and recipient addresses
- Transaction hashes and confirmation status
- Customer payment history
- Conversion rates at time of payment
- Webhook delivery logs
- Analytics and reporting data
The database doesn’t hold private keys or sensitive wallet information, only transaction metadata for tracking and reporting.
Webhook System
DePay sends webhook notifications to your application when payment events occur:
- Payment initiated
- Transaction broadcasted to blockchain
- Transaction confirmed (1, 3, 6+ confirmations)
- Payment completed
- Payment failed or expired
Webhooks include transaction details, allowing your application to fulfill orders, unlock content, or trigger other business logic.
Price Oracle Integration
Real-time cryptocurrency prices are fetched from:
- CoinGecko API
- CoinMarketCap
- Chainlink price feeds (on-chain oracles)
- DEX price discovery
Price data ensures accurate payment amounts in fiat-equivalent terms and enables proper token conversion calculations.
Data Flow
- Your application requests payment creation through API
- DePay server generates unique payment session with recipient address
- Customer opens payment widget and connects wallet
- Customer selects payment token (may differ from requested token)
- DePay calculates token swap route if needed
- Smart contract interaction initiated from customer wallet
- Transaction broadcasted to blockchain
- DePay monitors blockchain for transaction appearance
- After confirmations, payment marked as complete
- Webhook sent to your application with payment details
- Your application fulfills order or unlocks service
Security Considerations
DePay’s security model relies on:
- Non-custodial Architecture: No private keys stored on server
- Smart Contract Audits: Payment routing contracts professionally audited
- Transaction Verification: All payments verified on-chain
- Webhook Signatures: HMAC signatures prevent webhook spoofing
- Rate Limiting: API protection against abuse
- SSL/TLS: Encrypted communication for API calls
- Environment Isolation: Separate keys for production vs development
Storage Requirements
DePay requires persistent storage for:
- Database: Transaction records and payment history
- Configuration: Blockchain RPC endpoints and API settings
- Logs: Payment processing logs and error tracking
- Webhook Queue: Pending webhook deliveries
A typical deployment needs 1-5GB of storage initially, growing based on transaction volume.
Installation and Setup
Let’s walk through setting up DePay for deployment on Klutch.sh.
Step 1: Create the Project Structure
First, create a new directory for your DePay deployment:
mkdir depay-deploymentcd depay-deploymentgit initStep 2: Create the Dockerfile
Create a Dockerfile in the root directory:
FROM node:18-alpine
# Set environment variablesENV NODE_ENV=production \ PORT=3000
# Install system dependenciesRUN apk add --no-cache \ python3 \ make \ g++ \ git \ curl
# Create app directoryWORKDIR /app
# Create app userRUN addgroup -g 1000 depay && \ adduser -D -u 1000 -G depay depay
# Copy package filesCOPY package*.json ./
# Install dependenciesRUN npm ci --only=production && \ npm cache clean --force
# Copy application codeCOPY --chown=depay:depay . .
# Create necessary directoriesRUN mkdir -p logs data && \ chown -R depay:depay /app
# Switch to app userUSER depay
# Expose portEXPOSE 3000
# Health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \ CMD node healthcheck.js || exit 1
# Start applicationCMD ["node", "server.js"]Step 3: Create Package.json
Create package.json with dependencies:
{ "name": "depay-gateway", "version": "1.0.0", "description": "DePay cryptocurrency payment gateway", "main": "server.js", "scripts": { "start": "node server.js", "dev": "nodemon server.js", "test": "jest" }, "dependencies": { "express": "^4.18.2", "cors": "^2.8.5", "helmet": "^7.1.0", "dotenv": "^16.3.1", "ethers": "^6.9.0", "web3": "^4.3.0", "@solana/web3.js": "^1.87.6", "mongoose": "^8.0.3", "pg": "^8.11.3", "axios": "^1.6.2", "bull": "^4.12.0", "ioredis": "^5.3.2", "express-rate-limit": "^7.1.5", "express-validator": "^7.0.1", "winston": "^3.11.0", "qrcode": "^1.5.3", "crypto": "^1.0.1", "uuid": "^9.0.1", "bignumber.js": "^9.1.2" }, "devDependencies": { "nodemon": "^3.0.2", "jest": "^29.7.0" }, "engines": { "node": ">=18.0.0", "npm": ">=9.0.0" }}Step 4: Create Environment Configuration
Create .env.example file:
# Server ConfigurationNODE_ENV=productionPORT=3000API_BASE_URL=https://example-app.klutch.sh
# Database Configuration (Choose one)# PostgreSQLDATABASE_URL=postgresql://username:password@host:5432/depay
# MongoDB# MONGODB_URI=mongodb://username:password@host:27017/depay
# Redis Configuration (for job queues)REDIS_URL=redis://redis-host:6379
# Blockchain RPC EndpointsETHEREUM_RPC_URL=https://mainnet.infura.io/v3/YOUR_INFURA_KEYBSC_RPC_URL=https://bsc-dataseed.binance.orgPOLYGON_RPC_URL=https://polygon-rpc.comSOLANA_RPC_URL=https://api.mainnet-beta.solana.comARBITRUM_RPC_URL=https://arb1.arbitrum.io/rpcOPTIMISM_RPC_URL=https://mainnet.optimism.io
# Fallback RPC Endpoints (optional)ETHEREUM_FALLBACK_RPC=https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_KEYPOLYGON_FALLBACK_RPC=https://polygon-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_KEY
# Payment ConfigurationDEFAULT_PAYMENT_RECEIVER=0x742d35Cc6634C0532925a3b844Bc454e4438f44ePAYMENT_TIMEOUT_MINUTES=30REQUIRED_CONFIRMATIONS=3MAX_SLIPPAGE_PERCENT=1.0
# Supported Tokens (comma-separated contract addresses)ETHEREUM_TOKENS=0xdAC17F958D2ee523a2206206994597C13D831ec7,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48BSC_TOKENS=0x55d398326f99059fF775485246999027B3197955,0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580dPOLYGON_TOKENS=0xc2132D05D31c914a87C6611C10748AEb04B58e8F,0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
# DEX Router AddressesUNISWAP_V3_ROUTER=0xE592427A0AEce92De3Edee1F18E0157C05861564PANCAKESWAP_ROUTER=0x10ED43C718714eb63d5aA57B78B54704E256024EQUICKSWAP_ROUTER=0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff
# Price Oracle ConfigurationCOINGECKO_API_KEY=your-coingecko-api-keyCOINMARKETCAP_API_KEY=your-cmc-api-keyPRICE_UPDATE_INTERVAL=60000
# Webhook ConfigurationWEBHOOK_SECRET=your-webhook-secret-keyWEBHOOK_RETRY_ATTEMPTS=3WEBHOOK_TIMEOUT_MS=5000
# SecurityAPI_KEY_HEADER=X-API-KeyRATE_LIMIT_WINDOW_MS=900000RATE_LIMIT_MAX_REQUESTS=100CORS_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
# LoggingLOG_LEVEL=infoLOG_FILE_PATH=/app/logs/depay.log
# Feature FlagsENABLE_TOKEN_SWAPS=trueENABLE_MULTI_CHAIN=trueENABLE_WEBHOOK_SIGNATURES=trueENABLE_PRICE_ORACLE=trueStep 5: Create Main Server File
Create server.js:
const express = require('express');const helmet = require('helmet');const cors = require('cors');const rateLimit = require('express-rate-limit');require('dotenv').config();
const logger = require('./utils/logger');const errorHandler = require('./middleware/errorHandler');const paymentsRouter = require('./routes/payments');const webhooksRouter = require('./routes/webhooks');const blockchainRouter = require('./routes/blockchain');const { initializeDatabase } = require('./config/database');const { startBlockchainMonitor } = require('./services/blockchainMonitor');
const app = express();const PORT = process.env.PORT || 3000;
// Security middlewareapp.use(helmet());app.use(cors({ origin: process.env.CORS_ORIGINS?.split(',') || '*', credentials: true}));
// Rate limitingconst limiter = rateLimit({ windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS) || 900000, max: parseInt(process.env.RATE_LIMIT_MAX_REQUESTS) || 100, message: 'Too many requests from this IP'});app.use('/api/', limiter);
// Body parsingapp.use(express.json());app.use(express.urlencoded({ extended: true }));
// Request loggingapp.use((req, res, next) => { logger.info(`${req.method} ${req.path}`, { ip: req.ip, userAgent: req.get('user-agent') }); next();});
// Health check endpointapp.get('/health', (req, res) => { res.json({ status: 'healthy', timestamp: new Date().toISOString(), uptime: process.uptime() });});
// API routesapp.use('/api/payments', paymentsRouter);app.use('/api/webhooks', webhooksRouter);app.use('/api/blockchain', blockchainRouter);
// Root endpointapp.get('/', (req, res) => { res.json({ name: 'DePay Gateway', version: '1.0.0', documentation: `${process.env.API_BASE_URL}/api/docs` });});
// Error handlingapp.use(errorHandler);
// Initialize servicesasync function initialize() { try { // Connect to database await initializeDatabase(); logger.info('Database connected successfully');
// Start blockchain monitoring service if (process.env.ENABLE_BLOCKCHAIN_MONITOR !== 'false') { await startBlockchainMonitor(); logger.info('Blockchain monitor started'); }
// Start server app.listen(PORT, '0.0.0.0', () => { logger.info(`DePay server running on port ${PORT}`); logger.info(`Environment: ${process.env.NODE_ENV}`); }); } catch (error) { logger.error('Failed to initialize server:', error); process.exit(1); }}
// Graceful shutdownprocess.on('SIGTERM', async () => { logger.info('SIGTERM received, shutting down gracefully'); process.exit(0);});
process.on('SIGINT', async () => { logger.info('SIGINT received, shutting down gracefully'); process.exit(0);});
// Handle uncaught errorsprocess.on('uncaughtException', (error) => { logger.error('Uncaught Exception:', error); process.exit(1);});
process.on('unhandledRejection', (reason, promise) => { logger.error('Unhandled Rejection at:', promise, 'reason:', reason);});
// Start applicationinitialize();
module.exports = app;Step 6: Create Payment Routes
Create routes/payments.js:
const express = require('express');const { body, validationResult } = require('express-validator');const router = express.Router();const PaymentService = require('../services/paymentService');const logger = require('../utils/logger');
// Create payment requestrouter.post('/create', [ body('amount').isFloat({ min: 0 }).notEmpty(), body('currency').isString().notEmpty(), body('receiverAddress').isEthereumAddress(), body('network').isIn(['ethereum', 'bsc', 'polygon', 'solana', 'arbitrum', 'optimism']), body('metadata').optional().isObject() ], async (req, res, next) => { try { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ errors: errors.array() }); }
const payment = await PaymentService.createPayment(req.body);
logger.info('Payment created:', { paymentId: payment.id, amount: payment.amount, network: payment.network });
res.status(201).json({ success: true, payment: { id: payment.id, amount: payment.amount, currency: payment.currency, receiverAddress: payment.receiverAddress, network: payment.network, status: payment.status, expiresAt: payment.expiresAt, paymentUrl: payment.paymentUrl } }); } catch (error) { next(error); } });
// Get payment statusrouter.get('/:paymentId', async (req, res, next) => { try { const payment = await PaymentService.getPayment(req.params.paymentId);
if (!payment) { return res.status(404).json({ success: false, error: 'Payment not found' }); }
res.json({ success: true, payment: { id: payment.id, amount: payment.amount, currency: payment.currency, status: payment.status, txHash: payment.txHash, confirmations: payment.confirmations, createdAt: payment.createdAt, completedAt: payment.completedAt } }); } catch (error) { next(error); }});
// List paymentsrouter.get('/', async (req, res, next) => { try { const { page = 1, limit = 20, status, network } = req.query;
const payments = await PaymentService.listPayments({ page: parseInt(page), limit: parseInt(limit), status, network });
res.json({ success: true, payments: payments.data, pagination: { page: payments.page, limit: payments.limit, total: payments.total, pages: payments.pages } }); } catch (error) { next(error); }});
// Cancel paymentrouter.post('/:paymentId/cancel', async (req, res, next) => { try { const payment = await PaymentService.cancelPayment(req.params.paymentId);
res.json({ success: true, payment: { id: payment.id, status: payment.status } }); } catch (error) { next(error); }});
module.exports = router;Step 7: Create Blockchain Service
Create services/blockchainService.js:
const { ethers } = require('ethers');const { Connection, PublicKey, clusterApiUrl } = require('@solana/web3.js');const logger = require('../utils/logger');
class BlockchainService { constructor() { this.providers = {}; this.initializeProviders(); }
initializeProviders() { // Ethereum if (process.env.ETHEREUM_RPC_URL) { this.providers.ethereum = new ethers.JsonRpcProvider( process.env.ETHEREUM_RPC_URL ); }
// Binance Smart Chain if (process.env.BSC_RPC_URL) { this.providers.bsc = new ethers.JsonRpcProvider( process.env.BSC_RPC_URL ); }
// Polygon if (process.env.POLYGON_RPC_URL) { this.providers.polygon = new ethers.JsonRpcProvider( process.env.POLYGON_RPC_URL ); }
// Solana if (process.env.SOLANA_RPC_URL) { this.providers.solana = new Connection( process.env.SOLANA_RPC_URL, 'confirmed' ); }
// Arbitrum if (process.env.ARBITRUM_RPC_URL) { this.providers.arbitrum = new ethers.JsonRpcProvider( process.env.ARBITRUM_RPC_URL ); }
// Optimism if (process.env.OPTIMISM_RPC_URL) { this.providers.optimism = new ethers.JsonRpcProvider( process.env.OPTIMISM_RPC_URL ); } }
getProvider(network) { const provider = this.providers[network]; if (!provider) { throw new Error(`Provider not configured for network: ${network}`); } return provider; }
async getTransaction(txHash, network) { try { if (network === 'solana') { const connection = this.getProvider('solana'); const tx = await connection.getTransaction(txHash); return tx; } else { const provider = this.getProvider(network); const tx = await provider.getTransaction(txHash); return tx; } } catch (error) { logger.error(`Error fetching transaction ${txHash} on ${network}:`, error); throw error; } }
async getTransactionReceipt(txHash, network) { try { const provider = this.getProvider(network); const receipt = await provider.getTransactionReceipt(txHash); return receipt; } catch (error) { logger.error(`Error fetching receipt for ${txHash} on ${network}:`, error); throw error; } }
async getBlockNumber(network) { try { if (network === 'solana') { const connection = this.getProvider('solana'); return await connection.getSlot(); } else { const provider = this.getProvider(network); return await provider.getBlockNumber(); } } catch (error) { logger.error(`Error fetching block number on ${network}:`, error); throw error; } }
async getBalance(address, network, tokenAddress = null) { try { const provider = this.getProvider(network);
if (tokenAddress) { // ERC-20 token balance const tokenAbi = [ 'function balanceOf(address owner) view returns (uint256)' ]; const tokenContract = new ethers.Contract(tokenAddress, tokenAbi, provider); const balance = await tokenContract.balanceOf(address); return balance; } else { // Native token balance if (network === 'solana') { const connection = this.getProvider('solana'); const publicKey = new PublicKey(address); const balance = await connection.getBalance(publicKey); return balance; } else { const balance = await provider.getBalance(address); return balance; } } } catch (error) { logger.error(`Error fetching balance for ${address} on ${network}:`, error); throw error; } }
async estimateGas(transaction, network) { try { const provider = this.getProvider(network); const gasEstimate = await provider.estimateGas(transaction); return gasEstimate; } catch (error) { logger.error(`Error estimating gas on ${network}:`, error); throw error; } }
async getGasPrice(network) { try { const provider = this.getProvider(network); const feeData = await provider.getFeeData(); return feeData; } catch (error) { logger.error(`Error fetching gas price on ${network}:`, error); throw error; } }
async waitForTransaction(txHash, network, confirmations = 1) { try { if (network === 'solana') { const connection = this.getProvider('solana'); const confirmation = await connection.confirmTransaction(txHash, 'confirmed'); return confirmation; } else { const provider = this.getProvider(network); const receipt = await provider.waitForTransaction(txHash, confirmations); return receipt; } } catch (error) { logger.error(`Error waiting for transaction ${txHash} on ${network}:`, error); throw error; } }
isValidAddress(address, network) { try { if (network === 'solana') { new PublicKey(address); return true; } else { return ethers.isAddress(address); } } catch { return false; } }}
module.exports = new BlockchainService();Step 8: Create Health Check
Create healthcheck.js:
const http = require('http');
const options = { host: 'localhost', port: process.env.PORT || 3000, path: '/health', timeout: 2000};
const request = http.request(options, (res) => { console.log(`Health check status: ${res.statusCode}`); if (res.statusCode === 200) { process.exit(0); } else { process.exit(1); }});
request.on('error', (err) => { console.error('Health check failed:', err); process.exit(1);});
request.end();Step 9: Create Logger Utility
Create utils/logger.js:
const winston = require('winston');
const logger = winston.createLogger({ level: process.env.LOG_LEVEL || 'info', format: winston.format.combine( winston.format.timestamp(), winston.format.errors({ stack: true }), winston.format.json() ), defaultMeta: { service: 'depay-gateway' }, transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.colorize(), winston.format.simple() ) }) ]});
// Add file transport in productionif (process.env.NODE_ENV === 'production' && process.env.LOG_FILE_PATH) { logger.add(new winston.transports.File({ filename: process.env.LOG_FILE_PATH, maxsize: 10485760, // 10MB maxFiles: 5 }));}
module.exports = logger;Step 10: Create .dockerignore
Create .dockerignore:
node_modulesnpm-debug.log.git.gitignore.env.env.local*.mdREADME.md.DS_StoreThumbs.dblogs/*.log.vscode.ideacoverage/test/.dockerignoreDockerfiledocker-compose.ymlStep 11: Create Documentation
Create README.md:
# DePay Gateway
Decentralized payment gateway for accepting cryptocurrency payments.
## Features
- Multi-chain support (Ethereum, BSC, Polygon, Solana, etc.)- Direct wallet-to-wallet payments- Automatic token swapping- Real-time payment tracking- Webhook notifications- REST API- Non-custodial architecture
## Supported Networks
- Ethereum- Binance Smart Chain- Polygon- Solana- Arbitrum- Optimism
## Configuration
Set environment variables for:- Blockchain RPC endpoints- Database connection- Redis for job queues- Payment receiver addresses- Webhook secrets
## API Endpoints
- POST /api/payments/create - Create payment- GET /api/payments/:id - Get payment status- GET /api/payments - List payments- POST /api/webhooks/register - Register webhook
## Deployment
This application is configured to deploy on Klutch.sh with automatic Docker detection.Step 12: Initialize Git Repository
git add .git commit -m "Initial DePay gateway setup for Klutch.sh deployment"git branch -M mastergit remote add origin https://github.com/yourusername/depay-deployment.gitgit push -u origin masterDeploying to Klutch.sh
Now that your DePay gateway is configured, let’s deploy it to Klutch.sh.
-
Log in to Klutch.sh
Navigate to klutch.sh/app and sign in with your GitHub account.
-
Create a New Project
Click “New Project” and select “Import from GitHub”. Choose the repository containing your DePay deployment.
-
Configure Build Settings
Klutch.sh will automatically detect the Dockerfile in your repository. The platform will use this for building your container.
-
Configure Traffic Settings
Select “HTTP” as the traffic type. DePay serves its API on port 3000, and Klutch.sh will route HTTPS traffic to this port.
-
Set Environment Variables
In the project settings, add the following environment variables:
NODE_ENV:productionPORT:3000API_BASE_URL: Your Klutch.sh domain (e.g.,https://example-app.klutch.sh)
Database configuration:
DATABASE_URL:postgresql://username:password@host:port/depay
Redis configuration:
REDIS_URL:redis://redis-host:6379
Blockchain RPC endpoints (required):
ETHEREUM_RPC_URL:https://mainnet.infura.io/v3/YOUR_KEYBSC_RPC_URL:https://bsc-dataseed.binance.orgPOLYGON_RPC_URL:https://polygon-rpc.comSOLANA_RPC_URL:https://api.mainnet-beta.solana.com
Payment configuration:
DEFAULT_PAYMENT_RECEIVER: Your wallet address for receiving paymentsPAYMENT_TIMEOUT_MINUTES:30REQUIRED_CONFIRMATIONS:3
Security:
WEBHOOK_SECRET: Generate usingopenssl rand -hex 32API_KEY_HEADER:X-API-KeyCORS_ORIGINS:https://yourdomain.com
API keys (optional but recommended):
COINGECKO_API_KEY: Your CoinGecko API key for price feedsCOINMARKETCAP_API_KEY: Your CoinMarketCap API key
-
Configure Persistent Storage
DePay requires persistent storage for logs and data:
- Logs Volume:
- Mount path:
/app/logs - Size:
2GB
- Mount path:
- Data Volume:
- Mount path:
/app/data - Size:
5GB
- Mount path:
These volumes ensure your transaction logs and cached data persist across deployments.
- Logs Volume:
-
Deploy the Application
Click “Deploy” to start the build process. Klutch.sh will:
- Clone your repository
- Build the Docker image using your Dockerfile
- Install Node.js dependencies
- Deploy the container
- Provision an HTTPS endpoint
The build process typically takes 3-5 minutes.
-
Verify Deployment
Once deployment completes, test your DePay gateway:
- Visit
https://example-app.klutch.sh/healthto check server status - Access
https://example-app.klutch.shto see API information - Test payment creation through the API
- Visit
-
Configure Webhooks
Set up webhook endpoints in your application to receive payment notifications from your DePay gateway.
Getting Started with DePay
Once your DePay gateway is deployed, here’s how to integrate it into your application:
Creating a Payment
API Request
Create a payment request using the REST API:
curl -X POST https://example-app.klutch.sh/api/payments/create \ -H "Content-Type: application/json" \ -H "X-API-Key: your-api-key" \ -d '{ "amount": 100.00, "currency": "USDC", "receiverAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "network": "polygon", "metadata": { "orderId": "ORDER-12345", "customerEmail": "customer@example.com" } }'Response
{ "success": true, "payment": { "id": "pay_abc123xyz", "amount": 100.00, "currency": "USDC", "receiverAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e", "network": "polygon", "status": "pending", "expiresAt": "2025-12-07T18:30:00Z", "paymentUrl": "https://example-app.klutch.sh/pay/pay_abc123xyz" }}JavaScript SDK Integration
Install SDK
npm install @depay/web3-paymentsInitialize Payment Widget
import { Payment } from '@depay/web3-payments';
const payment = await Payment({ amount: { token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', // USDC on Ethereum value: 100.00 }, receiver: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e',
// Payment accepted callback accepted: ({ transaction }) => { console.log('Payment accepted:', transaction); },
// Payment completed callback confirmed: ({ transaction }) => { console.log('Payment confirmed:', transaction); // Fulfill order or unlock content },
// Payment failed callback failed: ({ error }) => { console.error('Payment failed:', error); }});React Integration
Create a payment component:
import React, { useState } from 'react';import { Payment } from '@depay/web3-payments';
function PaymentButton({ amount, orderId }) { const [status, setStatus] = useState('idle');
const handlePayment = async () => { try { setStatus('processing');
const payment = await Payment({ amount: { token: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', value: amount }, receiver: process.env.REACT_APP_PAYMENT_RECEIVER,
accepted: ({ transaction }) => { setStatus('accepted'); console.log('Transaction broadcasted:', transaction.id); },
confirmed: ({ transaction }) => { setStatus('completed'); // Send confirmation to your backend fetch('/api/orders/confirm', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ orderId, txHash: transaction.id }) }); },
failed: ({ error }) => { setStatus('failed'); console.error('Payment failed:', error); } }); } catch (error) { setStatus('error'); console.error('Error initiating payment:', error); } };
return ( <div> <button onClick={handlePayment} disabled={status === 'processing'} > {status === 'idle' && `Pay $${amount} with Crypto`} {status === 'processing' && 'Processing...'} {status === 'accepted' && 'Confirming...'} {status === 'completed' && 'Payment Complete!'} {status === 'failed' && 'Payment Failed'} </button>
{status === 'accepted' && ( <p>Transaction submitted. Waiting for confirmations...</p> )} </div> );}
export default PaymentButton;Checking Payment Status
API Request
curl https://example-app.klutch.sh/api/payments/pay_abc123xyz \ -H "X-API-Key: your-api-key"Response
{ "success": true, "payment": { "id": "pay_abc123xyz", "amount": 100.00, "currency": "USDC", "status": "confirmed", "txHash": "0x1234567890abcdef...", "confirmations": 6, "createdAt": "2025-12-07T17:00:00Z", "completedAt": "2025-12-07T17:05:30Z" }}Webhook Integration
DePay sends webhooks when payment events occur. Set up an endpoint in your application:
Express.js Webhook Handler
const express = require('express');const crypto = require('crypto');const router = express.Router();
// Verify webhook signaturefunction verifyWebhookSignature(payload, signature, secret) { const hmac = crypto.createHmac('sha256', secret); const digest = hmac.update(JSON.stringify(payload)).digest('hex'); return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(digest) );}
router.post('/webhooks/depay', express.json(), (req, res) => { const signature = req.headers['x-depay-signature']; const webhookSecret = process.env.DEPAY_WEBHOOK_SECRET;
// Verify signature if (!verifyWebhookSignature(req.body, signature, webhookSecret)) { return res.status(401).json({ error: 'Invalid signature' }); }
const { event, payment } = req.body;
switch (event) { case 'payment.created': console.log('Payment created:', payment.id); break;
case 'payment.accepted': console.log('Payment transaction broadcasted:', payment.txHash); // Update order status to "processing" break;
case 'payment.confirmed': console.log('Payment confirmed:', payment.id); // Fulfill order fulfillOrder(payment.metadata.orderId); break;
case 'payment.failed': console.log('Payment failed:', payment.id); // Handle failed payment break; }
res.status(200).json({ received: true });});
async function fulfillOrder(orderId) { // Your order fulfillment logic console.log(`Fulfilling order ${orderId}`);}
module.exports = router;Multi-Token Support
Allow customers to pay with any supported token:
const payment = await Payment({ amount: { // Request payment in USD equivalent currency: 'USD', value: 100.00 },
// Accept multiple tokens accept: [ { blockchain: 'ethereum', token: 'USDC' }, { blockchain: 'ethereum', token: 'USDT' }, { blockchain: 'ethereum', token: 'DAI' }, { blockchain: 'polygon', token: 'USDC' }, { blockchain: 'bsc', token: 'BUSD' } ],
// Convert to your preferred token receive: { blockchain: 'polygon', token: 'USDC', receiver: '0x742d35Cc6634C0532925a3b844Bc454e4438f44e' }});The payment will automatically route through DEXes to convert from the customer’s chosen token to your preferred token.
QR Code for Mobile Wallets
Generate payment QR codes:
const QRCode = require('qrcode');
async function generatePaymentQR(paymentUrl) { try { const qrCode = await QRCode.toDataURL(paymentUrl, { errorCorrectionLevel: 'H', width: 300, margin: 2 }); return qrCode; } catch (error) { console.error('Error generating QR code:', error); }}
// Usageconst qrCode = await generatePaymentQR( 'https://example-app.klutch.sh/pay/pay_abc123xyz');
// Display in HTML// <img src="${qrCode}" alt="Payment QR Code" />Testing Payments
Use testnets for development:
// Testnet configurationconst testnetPayment = await Payment({ amount: { token: '0x...', // Testnet token address value: 1.0 }, receiver: '0x...', // Your testnet wallet network: 'goerli', // Or 'mumbai' for Polygon testnet
// Test mode flag test: true});Get testnet tokens from faucets:
- Ethereum Goerli: goerlifaucet.com
- Polygon Mumbai: faucet.polygon.technology
- BSC Testnet: testnet.binance.org/faucet-smart
Advanced Configuration
Custom Token Support
Add support for specific tokens:
Update Environment Variables
# Ethereum tokens (comma-separated addresses)ETHEREUM_TOKENS=0xdAC17F958D2ee523a2206206994597C13D831ec7,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0x6B175474E89094C44Da98b954EedeAC495271d0F
# BSC tokensBSC_TOKENS=0x55d398326f99059fF775485246999027B3197955,0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
# Polygon tokensPOLYGON_TOKENS=0xc2132D05D31c914a87C6611C10748AEb04B58e8F,0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174Token Configuration File
Create config/tokens.json:
{ "ethereum": [ { "symbol": "USDT", "address": "0xdAC17F958D2ee523a2206206994597C13D831ec7", "decimals": 6, "name": "Tether USD" }, { "symbol": "USDC", "address": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", "decimals": 6, "name": "USD Coin" }, { "symbol": "DAI", "address": "0x6B175474E89094C44Da98b954EedeAC495271d0F", "decimals": 18, "name": "Dai Stablecoin" } ], "polygon": [ { "symbol": "USDT", "address": "0xc2132D05D31c914a87C6611C10748AEb04B58e8F", "decimals": 6, "name": "Tether USD" }, { "symbol": "USDC", "address": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174", "decimals": 6, "name": "USD Coin" } ]}Price Oracle Configuration
Configure multiple price sources for redundancy:
# Primary price sourcePRICE_ORACLE_PRIMARY=coingecko
# Fallback sourcesPRICE_ORACLE_FALLBACK=coinmarketcap,chainlink
# Update interval (milliseconds)PRICE_UPDATE_INTERVAL=60000
# Price deviation threshold for alertsPRICE_DEVIATION_THRESHOLD=5Transaction Monitoring
Configure confirmation requirements per network:
# Confirmations requiredETHEREUM_CONFIRMATIONS=12BSC_CONFIRMATIONS=15POLYGON_CONFIRMATIONS=128SOLANA_CONFIRMATIONS=32ARBITRUM_CONFIRMATIONS=1OPTIMISM_CONFIRMATIONS=1
# Block time estimates (for timeout calculations)ETHEREUM_BLOCK_TIME=12BSC_BLOCK_TIME=3POLYGON_BLOCK_TIME=2Webhook Retry Configuration
Ensure reliable webhook delivery:
# Retry attempts for failed webhooksWEBHOOK_RETRY_ATTEMPTS=5
# Retry delays (milliseconds)WEBHOOK_RETRY_DELAYS=1000,5000,30000,300000,3600000
# Webhook timeoutWEBHOOK_TIMEOUT_MS=10000
# Enable signature verificationWEBHOOK_SIGNATURE_ENABLED=trueRate Limiting
Protect your API from abuse:
# General API rate limitRATE_LIMIT_WINDOW_MS=900000RATE_LIMIT_MAX_REQUESTS=100
# Payment creation rate limit (per IP)PAYMENT_CREATION_WINDOW_MS=3600000PAYMENT_CREATION_MAX_REQUESTS=10
# Status check rate limitSTATUS_CHECK_WINDOW_MS=60000STATUS_CHECK_MAX_REQUESTS=30Database Optimization
Configure connection pooling:
# PostgreSQLDATABASE_POOL_MIN=2DATABASE_POOL_MAX=10DATABASE_IDLE_TIMEOUT=30000DATABASE_CONNECTION_TIMEOUT=5000
# Enable query loggingDATABASE_LOG_QUERIES=falseDATABASE_SLOW_QUERY_MS=1000Caching Configuration
Use Redis for caching:
# Redis cachingREDIS_CACHE_ENABLED=trueREDIS_CACHE_TTL=300
# Cache specific dataCACHE_PRICES=trueCACHE_PRICES_TTL=60
CACHE_TRANSACTIONS=trueCACHE_TRANSACTIONS_TTL=30
CACHE_TOKEN_INFO=trueCACHE_TOKEN_INFO_TTL=3600Production Best Practices
Follow these recommendations for running DePay in production:
Security
Secure RPC Endpoints
Use authenticated RPC providers:
- Infura with project-specific API keys
- Alchemy with API keys and domain restrictions
- QuickNode with security features enabled
Never expose RPC URLs publicly.
API Authentication
Implement API key authentication:
const authenticateApiKey = (req, res, next) => { const apiKey = req.headers['x-api-key'];
if (!apiKey || !isValidApiKey(apiKey)) { return res.status(401).json({ error: 'Invalid API key' }); }
req.apiKey = apiKey; next();};
app.use('/api/', authenticateApiKey);Webhook Security
Always verify webhook signatures:
const verifyWebhook = (req, res, next) => { const signature = req.headers['x-webhook-signature']; const payload = JSON.stringify(req.body);
const expectedSignature = crypto .createHmac('sha256', process.env.WEBHOOK_SECRET) .update(payload) .digest('hex');
if (signature !== expectedSignature) { return res.status(401).json({ error: 'Invalid signature' }); }
next();};Environment Variable Security
- Never commit
.envfiles - Rotate API keys regularly
- Use strong webhook secrets (32+ characters)
- Restrict CORS origins to your domains only
Monitoring
Transaction Monitoring
Track key metrics:
- Payment success rate
- Average confirmation time
- Failed transaction rate
- Blockchain node latency
- Gas price trends
Application Monitoring
Monitor:
- API response times
- Error rates
- Memory usage
- Database query performance
- Webhook delivery success rate
Alerting
Set up alerts for:
- Failed payments above threshold
- Blockchain node connection issues
- High error rates
- Memory leaks
- Database connection failures
Reliability
RPC Endpoint Redundancy
Configure multiple RPC endpoints:
const providers = { ethereum: [ new ethers.JsonRpcProvider(process.env.ETHEREUM_RPC_PRIMARY), new ethers.JsonRpcProvider(process.env.ETHEREUM_RPC_FALLBACK) ]};
async function getProviderWithFallback(network) { for (const provider of providers[network]) { try { await provider.getBlockNumber(); return provider; } catch (error) { console.warn(`Provider failed, trying fallback...`); } } throw new Error('All providers failed');}Database Backups
Regular automated backups:
- Daily full backups
- Hourly incremental backups
- Backup retention: 30 days
- Test restore procedures monthly
Graceful Shutdown
Handle shutdown signals properly:
process.on('SIGTERM', async () => { console.log('SIGTERM received, shutting down gracefully');
// Stop accepting new requests server.close();
// Finish processing active transactions await blockchainMonitor.stop();
// Close database connections await database.close();
process.exit(0);});Performance
Connection Pooling
Use connection pools for databases and RPC endpoints:
const pool = new Pool({ connectionString: process.env.DATABASE_URL, max: 20, idleTimeoutMillis: 30000, connectionTimeoutMillis: 2000});Request Caching
Cache frequent requests:
const NodeCache = require('node-cache');const priceCache = new NodeCache({ stdTTL: 60 });
async function getTokenPrice(symbol) { const cached = priceCache.get(symbol); if (cached) return cached;
const price = await fetchPriceFromOracle(symbol); priceCache.set(symbol, price); return price;}Background Jobs
Use job queues for heavy operations:
const Queue = require('bull');const transactionQueue = new Queue('transactions', process.env.REDIS_URL);
// ProducertransactionQueue.add('monitor', { txHash: '0x...', network: 'ethereum'});
// ConsumertransactionQueue.process('monitor', async (job) => { const { txHash, network } = job.data; await monitorTransaction(txHash, network);});Scaling
Horizontal Scaling
Deploy multiple instances:
- Load balancer distributes requests
- Shared database and Redis
- Stateless application design
- Session storage in Redis
Database Scaling
For high transaction volumes:
- Read replicas for queries
- Write to primary database
- Connection pooling
- Query optimization with indexes
Caching Strategy
Multi-level caching:
- Application-level caching (node-cache)
- Distributed caching (Redis)
- CDN for static assets
Troubleshooting
Connection Issues
Problem: Cannot connect to blockchain network
Solutions:
- Verify RPC endpoint URL is correct
- Check API key is valid and not rate-limited
- Test connectivity:
curl -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' YOUR_RPC_URL - Try fallback RPC endpoint
- Check firewall rules
- Verify network is not experiencing downtime
Problem: Database connection failed
Solutions:
- Verify DATABASE_URL format
- Check database credentials
- Ensure database server is running
- Test connection with psql or mongo cli
- Check network connectivity
- Review database server logs
Payment Issues
Problem: Payment not detected
Solutions:
- Verify transaction was broadcasted (check on block explorer)
- Confirm correct network (mainnet vs testnet)
- Check receiver address matches
- Ensure sufficient confirmations have passed
- Review blockchain monitor logs
- Verify RPC endpoint is synced
Problem: Token swap failed
Solutions:
- Check slippage tolerance settings
- Verify DEX router has liquidity for token pair
- Ensure token addresses are correct
- Review gas estimation
- Check for token approval issues
- Test swap on DEX interface directly
Problem: Payment timeout
Solutions:
- Extend payment timeout duration
- Check if transaction is still pending on blockchain
- Review gas price settings (may be too low)
- Verify customer has sufficient funds
- Check for network congestion
Webhook Issues
Problem: Webhooks not received
Solutions:
- Verify webhook URL is accessible from internet
- Check webhook endpoint returns 200 status
- Review webhook logs in DePay dashboard
- Test webhook signature verification
- Ensure endpoint handles POST requests
- Check for firewall blocking
- Review application logs for errors
Problem: Duplicate webhooks
Solutions:
- Implement idempotency using payment ID
- Store processed webhook IDs
- Use database transactions for webhook handling
- Return 200 status only after successful processing
Performance Issues
Problem: Slow API responses
Solutions:
- Enable caching for frequently accessed data
- Add database indexes on query fields
- Use connection pooling
- Optimize slow database queries
- Increase server resources
- Implement request queuing
- Use CDN for static assets
Problem: High memory usage
Solutions:
- Review for memory leaks
- Limit cache size
- Implement pagination for large datasets
- Use streams for large file processing
- Monitor with memory profiling tools
- Restart application periodically
- Increase container memory
Additional Resources
- DePay Official Website
- DePay Documentation
- DePay GitHub
- Ethers.js Documentation
- Web3.js Documentation
- Solana Documentation
- Klutch.sh Documentation
- Persistent Volumes Guide
Conclusion
DePay brings the power of decentralized payments to your application, letting you accept cryptocurrency without giving up control of your funds. Unlike traditional payment processors that act as middlemen, DePay enables direct peer-to-peer transactions where payments flow straight from your customers to your wallet. This eliminates counterparty risk, reduces fees, and maintains the core principles of cryptocurrency: decentralization and self-custody.
Deploying DePay on Klutch.sh gives you the infrastructure to run a production-grade payment gateway without managing servers or worrying about scaling. Your payment infrastructure is always available, always secure, and ready to process transactions across multiple blockchain networks. Whether you’re building an e-commerce platform, subscription service, or any application requiring crypto payments, DePay provides the tools to accept digital assets while maintaining complete control.
Start accepting cryptocurrency payments today and tap into the global digital economy without intermediaries or excessive fees.