Skip to content

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

  1. Your application requests payment creation through API
  2. DePay server generates unique payment session with recipient address
  3. Customer opens payment widget and connects wallet
  4. Customer selects payment token (may differ from requested token)
  5. DePay calculates token swap route if needed
  6. Smart contract interaction initiated from customer wallet
  7. Transaction broadcasted to blockchain
  8. DePay monitors blockchain for transaction appearance
  9. After confirmations, payment marked as complete
  10. Webhook sent to your application with payment details
  11. 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:

Terminal window
mkdir depay-deployment
cd depay-deployment
git init

Step 2: Create the Dockerfile

Create a Dockerfile in the root directory:

FROM node:18-alpine
# Set environment variables
ENV NODE_ENV=production \
PORT=3000
# Install system dependencies
RUN apk add --no-cache \
python3 \
make \
g++ \
git \
curl
# Create app directory
WORKDIR /app
# Create app user
RUN addgroup -g 1000 depay && \
adduser -D -u 1000 -G depay depay
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production && \
npm cache clean --force
# Copy application code
COPY --chown=depay:depay . .
# Create necessary directories
RUN mkdir -p logs data && \
chown -R depay:depay /app
# Switch to app user
USER depay
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD node healthcheck.js || exit 1
# Start application
CMD ["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:

Terminal window
# Server Configuration
NODE_ENV=production
PORT=3000
API_BASE_URL=https://example-app.klutch.sh
# Database Configuration (Choose one)
# PostgreSQL
DATABASE_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 Endpoints
ETHEREUM_RPC_URL=https://mainnet.infura.io/v3/YOUR_INFURA_KEY
BSC_RPC_URL=https://bsc-dataseed.binance.org
POLYGON_RPC_URL=https://polygon-rpc.com
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
ARBITRUM_RPC_URL=https://arb1.arbitrum.io/rpc
OPTIMISM_RPC_URL=https://mainnet.optimism.io
# Fallback RPC Endpoints (optional)
ETHEREUM_FALLBACK_RPC=https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_KEY
POLYGON_FALLBACK_RPC=https://polygon-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_KEY
# Payment Configuration
DEFAULT_PAYMENT_RECEIVER=0x742d35Cc6634C0532925a3b844Bc454e4438f44e
PAYMENT_TIMEOUT_MINUTES=30
REQUIRED_CONFIRMATIONS=3
MAX_SLIPPAGE_PERCENT=1.0
# Supported Tokens (comma-separated contract addresses)
ETHEREUM_TOKENS=0xdAC17F958D2ee523a2206206994597C13D831ec7,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
BSC_TOKENS=0x55d398326f99059fF775485246999027B3197955,0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
POLYGON_TOKENS=0xc2132D05D31c914a87C6611C10748AEb04B58e8F,0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174
# DEX Router Addresses
UNISWAP_V3_ROUTER=0xE592427A0AEce92De3Edee1F18E0157C05861564
PANCAKESWAP_ROUTER=0x10ED43C718714eb63d5aA57B78B54704E256024E
QUICKSWAP_ROUTER=0xa5E0829CaCEd8fFDD4De3c43696c57F7D7A678ff
# Price Oracle Configuration
COINGECKO_API_KEY=your-coingecko-api-key
COINMARKETCAP_API_KEY=your-cmc-api-key
PRICE_UPDATE_INTERVAL=60000
# Webhook Configuration
WEBHOOK_SECRET=your-webhook-secret-key
WEBHOOK_RETRY_ATTEMPTS=3
WEBHOOK_TIMEOUT_MS=5000
# Security
API_KEY_HEADER=X-API-Key
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
CORS_ORIGINS=https://yourdomain.com,https://app.yourdomain.com
# Logging
LOG_LEVEL=info
LOG_FILE_PATH=/app/logs/depay.log
# Feature Flags
ENABLE_TOKEN_SWAPS=true
ENABLE_MULTI_CHAIN=true
ENABLE_WEBHOOK_SIGNATURES=true
ENABLE_PRICE_ORACLE=true

Step 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 middleware
app.use(helmet());
app.use(cors({
origin: process.env.CORS_ORIGINS?.split(',') || '*',
credentials: true
}));
// Rate limiting
const 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 parsing
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Request logging
app.use((req, res, next) => {
logger.info(`${req.method} ${req.path}`, {
ip: req.ip,
userAgent: req.get('user-agent')
});
next();
});
// Health check endpoint
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime()
});
});
// API routes
app.use('/api/payments', paymentsRouter);
app.use('/api/webhooks', webhooksRouter);
app.use('/api/blockchain', blockchainRouter);
// Root endpoint
app.get('/', (req, res) => {
res.json({
name: 'DePay Gateway',
version: '1.0.0',
documentation: `${process.env.API_BASE_URL}/api/docs`
});
});
// Error handling
app.use(errorHandler);
// Initialize services
async 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 shutdown
process.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 errors
process.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 application
initialize();
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 request
router.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 status
router.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 payments
router.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 payment
router.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 production
if (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_modules
npm-debug.log
.git
.gitignore
.env
.env.local
*.md
README.md
.DS_Store
Thumbs.db
logs/
*.log
.vscode
.idea
coverage/
test/
.dockerignore
Dockerfile
docker-compose.yml

Step 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

Terminal window
git add .
git commit -m "Initial DePay gateway setup for Klutch.sh deployment"
git branch -M master
git remote add origin https://github.com/yourusername/depay-deployment.git
git push -u origin master

Deploying to Klutch.sh

Now that your DePay gateway is configured, let’s deploy it to Klutch.sh.

  1. Log in to Klutch.sh

    Navigate to klutch.sh/app and sign in with your GitHub account.

  2. Create a New Project

    Click “New Project” and select “Import from GitHub”. Choose the repository containing your DePay deployment.

  3. Configure Build Settings

    Klutch.sh will automatically detect the Dockerfile in your repository. The platform will use this for building your container.

  4. 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.

  5. Set Environment Variables

    In the project settings, add the following environment variables:

    • NODE_ENV: production
    • PORT: 3000
    • API_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_KEY
    • BSC_RPC_URL: https://bsc-dataseed.binance.org
    • POLYGON_RPC_URL: https://polygon-rpc.com
    • SOLANA_RPC_URL: https://api.mainnet-beta.solana.com

    Payment configuration:

    • DEFAULT_PAYMENT_RECEIVER: Your wallet address for receiving payments
    • PAYMENT_TIMEOUT_MINUTES: 30
    • REQUIRED_CONFIRMATIONS: 3

    Security:

    • WEBHOOK_SECRET: Generate using openssl rand -hex 32
    • API_KEY_HEADER: X-API-Key
    • CORS_ORIGINS: https://yourdomain.com

    API keys (optional but recommended):

    • COINGECKO_API_KEY: Your CoinGecko API key for price feeds
    • COINMARKETCAP_API_KEY: Your CoinMarketCap API key
  6. Configure Persistent Storage

    DePay requires persistent storage for logs and data:

    • Logs Volume:
      • Mount path: /app/logs
      • Size: 2GB
    • Data Volume:
      • Mount path: /app/data
      • Size: 5GB

    These volumes ensure your transaction logs and cached data persist across deployments.

  7. 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.

  8. Verify Deployment

    Once deployment completes, test your DePay gateway:

    • Visit https://example-app.klutch.sh/health to check server status
    • Access https://example-app.klutch.sh to see API information
    • Test payment creation through the API
  9. 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:

Terminal window
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

Terminal window
npm install @depay/web3-payments

Initialize 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

Terminal window
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 signature
function 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);
}
}
// Usage
const 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 configuration
const 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:

Advanced Configuration

Custom Token Support

Add support for specific tokens:

Update Environment Variables

Terminal window
# Ethereum tokens (comma-separated addresses)
ETHEREUM_TOKENS=0xdAC17F958D2ee523a2206206994597C13D831ec7,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48,0x6B175474E89094C44Da98b954EedeAC495271d0F
# BSC tokens
BSC_TOKENS=0x55d398326f99059fF775485246999027B3197955,0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d
# Polygon tokens
POLYGON_TOKENS=0xc2132D05D31c914a87C6611C10748AEb04B58e8F,0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174

Token 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:

Terminal window
# Primary price source
PRICE_ORACLE_PRIMARY=coingecko
# Fallback sources
PRICE_ORACLE_FALLBACK=coinmarketcap,chainlink
# Update interval (milliseconds)
PRICE_UPDATE_INTERVAL=60000
# Price deviation threshold for alerts
PRICE_DEVIATION_THRESHOLD=5

Transaction Monitoring

Configure confirmation requirements per network:

Terminal window
# Confirmations required
ETHEREUM_CONFIRMATIONS=12
BSC_CONFIRMATIONS=15
POLYGON_CONFIRMATIONS=128
SOLANA_CONFIRMATIONS=32
ARBITRUM_CONFIRMATIONS=1
OPTIMISM_CONFIRMATIONS=1
# Block time estimates (for timeout calculations)
ETHEREUM_BLOCK_TIME=12
BSC_BLOCK_TIME=3
POLYGON_BLOCK_TIME=2

Webhook Retry Configuration

Ensure reliable webhook delivery:

Terminal window
# Retry attempts for failed webhooks
WEBHOOK_RETRY_ATTEMPTS=5
# Retry delays (milliseconds)
WEBHOOK_RETRY_DELAYS=1000,5000,30000,300000,3600000
# Webhook timeout
WEBHOOK_TIMEOUT_MS=10000
# Enable signature verification
WEBHOOK_SIGNATURE_ENABLED=true

Rate Limiting

Protect your API from abuse:

Terminal window
# General API rate limit
RATE_LIMIT_WINDOW_MS=900000
RATE_LIMIT_MAX_REQUESTS=100
# Payment creation rate limit (per IP)
PAYMENT_CREATION_WINDOW_MS=3600000
PAYMENT_CREATION_MAX_REQUESTS=10
# Status check rate limit
STATUS_CHECK_WINDOW_MS=60000
STATUS_CHECK_MAX_REQUESTS=30

Database Optimization

Configure connection pooling:

Terminal window
# PostgreSQL
DATABASE_POOL_MIN=2
DATABASE_POOL_MAX=10
DATABASE_IDLE_TIMEOUT=30000
DATABASE_CONNECTION_TIMEOUT=5000
# Enable query logging
DATABASE_LOG_QUERIES=false
DATABASE_SLOW_QUERY_MS=1000

Caching Configuration

Use Redis for caching:

Terminal window
# Redis caching
REDIS_CACHE_ENABLED=true
REDIS_CACHE_TTL=300
# Cache specific data
CACHE_PRICES=true
CACHE_PRICES_TTL=60
CACHE_TRANSACTIONS=true
CACHE_TRANSACTIONS_TTL=30
CACHE_TOKEN_INFO=true
CACHE_TOKEN_INFO_TTL=3600

Production 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 .env files
  • 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);
// Producer
transactionQueue.add('monitor', {
txHash: '0x...',
network: 'ethereum'
});
// Consumer
transactionQueue.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

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.