Balance Check Guide
Learn how to check your wallet balances and implement balance monitoring in your PayVanta integration.
Overview
The Balance Check API allows you to:
- Monitor your payin and payout wallet balances
- Validate sufficient funds before processing transactions
- Set up automated balance alerts and monitoring
- Track balance changes over time
- Implement balance-based business logic
Getting Started
Basic Balance Check
import axios from 'axios';
async function checkBalance() {
try {
const response = await axios.get('https://api.payvanta.in/balance-check', {
headers: {
'Authorization': `Bearer <base64_encoded_credentials>`,
'Content-Type': 'application/json'
}
});
const { payin_balance, payout_balance } = response.data;
console.log(`Payin Balance: ₹${payin_balance}`);
console.log(`Payout Balance: ₹${payout_balance}`);
return response.data;
} catch (error) {
console.error('Balance check failed:', error.message);
throw error;
}
}Response Format
{
"payin_balance": 490,
"payout_balance": 6.602000000000004
}Field Descriptions:
- payin_balance: Available funds for collecting payments from customers
- payout_balance: Available funds for sending money to bank accounts
Pre-Transaction Validation
Check Balance Before Payout
async function validatePayoutBalance(amount) {
try {
const balance = await checkBalance();
if (balance.payout_balance < amount) {
throw new Error(`Insufficient balance. Required: ₹${amount}, Available: ₹${balance.payout_balance}`);
}
console.log(`✅ Sufficient balance for payout of ₹${amount}`);
return true;
} catch (error) {
console.error('❌ Balance validation failed:', error.message);
return false;
}
}
// Usage example
async function processPayoutWithValidation(payoutData) {
const isValid = await validatePayoutBalance(payoutData.amount);
if (!isValid) {
return { success: false, error: 'Insufficient balance' };
}
// Proceed with payout
const payoutResult = await processPayout(payoutData);
return payoutResult;
}Balance Check Middleware
// Express.js middleware for balance validation
function balanceCheckMiddleware(requiredType, amountField = 'amount') {
return async (req, res, next) => {
try {
const balance = await checkBalance();
const requiredAmount = req.body[amountField];
const balanceField = requiredType === 'payout' ? 'payout_balance' : 'payin_balance';
if (balance[balanceField] < requiredAmount) {
return res.status(400).json({
success: false,
error: 'Insufficient balance',
required: requiredAmount,
available: balance[balanceField]
});
}
// Attach balance to request for further use
req.balance = balance;
next();
} catch (error) {
res.status(500).json({
success: false,
error: 'Balance check failed'
});
}
};
}
// Usage in routes
app.post('/api/payout', balanceCheckMiddleware('payout'), async (req, res) => {
// Balance is already validated, proceed with payout
const result = await processPayout(req.body);
res.json(result);
});Balance Monitoring
Real-time Balance Alerts
class BalanceMonitor {
constructor(options = {}) {
this.thresholds = {
payin_low: options.payinThreshold || 100,
payout_low: options.payoutThreshold || 50,
...options.thresholds
};
this.alertCallbacks = [];
this.monitoringInterval = null;
}
// Add alert callback
onAlert(callback) {
this.alertCallbacks.push(callback);
}
// Check balance and trigger alerts
async checkAndAlert() {
try {
const balance = await checkBalance();
// Check payin balance
if (balance.payin_balance < this.thresholds.payin_low) {
this.triggerAlert('payin_low', {
type: 'payin',
balance: balance.payin_balance,
threshold: this.thresholds.payin_low
});
}
// Check payout balance
if (balance.payout_balance < this.thresholds.payout_low) {
this.triggerAlert('payout_low', {
type: 'payout',
balance: balance.payout_balance,
threshold: this.thresholds.payout_low
});
}
return balance;
} catch (error) {
this.triggerAlert('check_failed', { error: error.message });
}
}
// Trigger alert callbacks
triggerAlert(alertType, data) {
this.alertCallbacks.forEach(callback => {
try {
callback(alertType, data);
} catch (error) {
console.error('Alert callback failed:', error);
}
});
}
// Start monitoring
startMonitoring(intervalMinutes = 5) {
if (this.monitoringInterval) {
this.stopMonitoring();
}
this.monitoringInterval = setInterval(() => {
this.checkAndAlert();
}, intervalMinutes * 60 * 1000);
// Initial check
this.checkAndAlert();
}
// Stop monitoring
stopMonitoring() {
if (this.monitoringInterval) {
clearInterval(this.monitoringInterval);
this.monitoringInterval = null;
}
}
}
// Usage example
const monitor = new BalanceMonitor({
payinThreshold: 200,
payoutThreshold: 100
});
// Set up alert handlers
monitor.onAlert((alertType, data) => {
switch (alertType) {
case 'payin_low':
console.warn(`🚨 Low payin balance: ₹${data.balance} (threshold: ₹${data.threshold})`);
// Send notification, email, etc.
break;
case 'payout_low':
console.warn(`🚨 Low payout balance: ₹${data.balance} (threshold: ₹${data.threshold})`);
// Send notification, email, etc.
break;
case 'check_failed':
console.error('❌ Balance check failed:', data.error);
// Handle error, retry, etc.
break;
}
});
// Start monitoring every 5 minutes
monitor.startMonitoring(5);Balance Tracking and Analytics
class BalanceTracker {
constructor() {
this.history = [];
}
// Record balance snapshot
async recordBalance() {
try {
const balance = await checkBalance();
const record = {
timestamp: new Date().toISOString(),
payin_balance: balance.payin_balance,
payout_balance: balance.payout_balance
};
this.history.push(record);
// Keep only last 100 records
if (this.history.length > 100) {
this.history = this.history.slice(-100);
}
return record;
} catch (error) {
console.error('Failed to record balance:', error);
}
}
// Get balance trend
getBalanceTrend(type = 'payout', periods = 10) {
const recent = this.history.slice(-periods);
if (recent.length < 2) return null;
const field = `${type}_balance`;
const first = recent[0][field];
const last = recent[recent.length - 1][field];
return {
change: last - first,
percentage: ((last - first) / first) * 100,
trend: last > first ? 'increasing' : 'decreasing'
};
}
// Get average balance
getAverageBalance(type = 'payout', periods = 10) {
const recent = this.history.slice(-periods);
if (recent.length === 0) return null;
const field = `${type}_balance`;
const sum = recent.reduce((acc, record) => acc + record[field], 0);
return sum / recent.length;
}
}
// Usage
const tracker = new BalanceTracker();
// Record balance every hour
setInterval(() => {
tracker.recordBalance();
}, 60 * 60 * 1000);Integration Patterns
React Hook for Balance Management
import { useState, useEffect, useCallback } from 'react';
function useBalance(autoRefresh = true, refreshInterval = 300000) { // 5 minutes
const [balance, setBalance] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const fetchBalance = useCallback(async () => {
setLoading(true);
setError(null);
try {
const balanceData = await checkBalance();
setBalance(balanceData);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
}, []);
// Auto-refresh balance
useEffect(() => {
fetchBalance(); // Initial fetch
if (autoRefresh) {
const interval = setInterval(fetchBalance, refreshInterval);
return () => clearInterval(interval);
}
}, [fetchBalance, autoRefresh, refreshInterval]);
return {
balance,
loading,
error,
refresh: fetchBalance
};
}
// Usage in React component
function BalanceDashboard() {
const { balance, loading, error, refresh } = useBalance();
if (loading && !balance) {
return <div>Loading balance...</div>;
}
if (error) {
return (
<div>
<p>Error: {error}</p>
<button onClick={refresh}>Retry</button>
</div>
);
}
return (
<div>
<h2>Wallet Balance</h2>
<div>
<p>Payin Balance: ₹{balance?.payin_balance || 0}</p>
<p>Payout Balance: ₹{balance?.payout_balance || 0}</p>
</div>
<button onClick={refresh} disabled={loading}>
{loading ? 'Refreshing...' : 'Refresh'}
</button>
</div>
);
}Python Balance Manager
import requests
import time
import threading
from datetime import datetime
import os
class BalanceManager:
def __init__(self, token=None):
self.token = token or os.getenv('PAYVANTA_TOKEN')
self.base_url = 'https://api.payvanta.in'
self.headers = {
'Authorization': f'Bearer {self.token}',
'Content-Type': 'application/json'
}
self.balance_cache = None
self.cache_timestamp = None
self.cache_duration = 60 # Cache for 60 seconds
def get_balance(self, use_cache=True):
"""Get current balance with optional caching"""
now = time.time()
if (use_cache and self.balance_cache and
self.cache_timestamp and
now - self.cache_timestamp < self.cache_duration):
return self.balance_cache
try:
response = requests.get(
f'{self.base_url}/balance-check',
headers=self.headers,
timeout=10
)
response.raise_for_status()
balance = response.json()
# Update cache
self.balance_cache = balance
self.cache_timestamp = now
return balance
except requests.exceptions.RequestException as e:
raise Exception(f"Balance check failed: {str(e)}")
def validate_payout_balance(self, amount):
"""Validate if payout balance is sufficient"""
balance = self.get_balance()
return balance['payout_balance'] >= amount
def get_balance_status(self, thresholds=None):
"""Get balance status with threshold checks"""
if thresholds is None:
thresholds = {'payin_low': 100, 'payout_low': 50}
balance = self.get_balance()
status = {
'balance': balance,
'timestamp': datetime.now().isoformat(),
'alerts': []
}
if balance['payin_balance'] < thresholds['payin_low']:
status['alerts'].append({
'type': 'payin_low',
'message': f"Payin balance ({balance['payin_balance']}) below threshold ({thresholds['payin_low']})"
})
if balance['payout_balance'] < thresholds['payout_low']:
status['alerts'].append({
'type': 'payout_low',
'message': f"Payout balance ({balance['payout_balance']}) below threshold ({thresholds['payout_low']})"
})
return status
# Usage example
balance_manager = BalanceManager()
# Check balance
try:
balance = balance_manager.get_balance()
print(f"Payin Balance: ₹{balance['payin_balance']}")
print(f"Payout Balance: ₹{balance['payout_balance']}")
# Validate before payout
if balance_manager.validate_payout_balance(100):
print("✅ Sufficient balance for payout")
else:
print("❌ Insufficient balance for payout")
except Exception as e:
print(f"Error: {e}")Best Practices
1. Caching Strategy
class BalanceCache {
constructor(cacheDurationMs = 60000) { // 1 minute default
this.cache = null;
this.cacheTimestamp = null;
this.cacheDuration = cacheDurationMs;
}
async getBalance(forceRefresh = false) {
const now = Date.now();
if (!forceRefresh &&
this.cache &&
this.cacheTimestamp &&
now - this.cacheTimestamp < this.cacheDuration) {
return this.cache;
}
// Fetch fresh balance
const balance = await checkBalance();
this.cache = balance;
this.cacheTimestamp = now;
return balance;
}
invalidateCache() {
this.cache = null;
this.cacheTimestamp = null;
}
}2. Error Handling and Retry Logic
async function robustBalanceCheck(maxRetries = 3, retryDelay = 1000) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await checkBalance();
} catch (error) {
console.warn(`Balance check attempt ${attempt} failed:`, error.message);
if (attempt === maxRetries) {
throw new Error(`Balance check failed after ${maxRetries} attempts: ${error.message}`);
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, retryDelay * attempt));
}
}
}3. Rate Limiting Compliance
class RateLimitedBalanceChecker {
constructor(maxRequestsPerMinute = 50) {
this.maxRequests = maxRequestsPerMinute;
this.requests = [];
}
async checkBalance() {
await this.waitForRateLimit();
const now = Date.now();
this.requests.push(now);
// Clean old requests
this.requests = this.requests.filter(time => now - time < 60000);
return await checkBalance();
}
async waitForRateLimit() {
const now = Date.now();
const recentRequests = this.requests.filter(time => now - time < 60000);
if (recentRequests.length >= this.maxRequests) {
const oldestRequest = Math.min(...recentRequests);
const waitTime = 60000 - (now - oldestRequest);
if (waitTime > 0) {
console.log(`Rate limit reached, waiting ${waitTime}ms`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
}
}Common Use Cases
1. Pre-Transaction Validation
Always check balance before processing payouts to avoid failed transactions:
async function validateAndProcessPayout(payoutData) {
const balance = await checkBalance();
if (balance.payout_balance < payoutData.amount) {
return {
success: false,
error: 'Insufficient balance',
required: payoutData.amount,
available: balance.payout_balance
};
}
return await processPayout(payoutData);
}2. Balance Alerts
Set up automated alerts for low balance:
function setupBalanceAlerts() {
setInterval(async () => {
try {
const balance = await checkBalance();
if (balance.payout_balance < 100) {
// Send email, SMS, or push notification
await sendAlert('Low payout balance', balance);
}
} catch (error) {
console.error('Balance alert check failed:', error);
}
}, 5 * 60 * 1000); // Check every 5 minutes
}3. Dashboard Integration
Display real-time balance in your admin dashboard:
// Dashboard API endpoint
app.get('/api/dashboard/balance', async (req, res) => {
try {
const balance = await checkBalance();
res.json({
success: true,
data: {
payin_balance: balance.payin_balance,
payout_balance: balance.payout_balance,
last_updated: new Date().toISOString()
}
});
} catch (error) {
res.status(500).json({
success: false,
error: 'Failed to fetch balance'
});
}
});Troubleshooting
Common Issues
-
Authentication Errors
- Verify Bearer token is correctly generated
- Check API credentials are valid
- Ensure token is properly formatted
-
Rate Limiting
- Implement caching to reduce API calls
- Add retry logic with exponential backoff
- Monitor your request frequency
-
Network Timeouts
- Set appropriate timeout values
- Implement retry mechanisms
- Handle network failures gracefully
Debug Example
async function debugBalanceCheck() {
console.log('🔍 Starting balance check debug...');
try {
console.log('📡 Making API request...');
const startTime = Date.now();
const balance = await checkBalance();
const responseTime = Date.now() - startTime;
console.log(`✅ Balance retrieved in ${responseTime}ms`);
console.log('💰 Balance data:', balance);
return balance;
} catch (error) {
console.error('❌ Balance check failed:', {
message: error.message,
status: error.response?.status,
data: error.response?.data
});
throw error;
}
}Next Steps
Support
For questions about balance checking or integration help, contact our support team at support@payvanta.in