Skip to main content

Overview

The wallet balance endpoint allows you to query the current available balance in your terminal’s wallet. This is useful for checking available funds before processing payments, displaying balance to users, and reconciliation purposes.
Check wallet balance before processing large payments to ensure sufficient funds are available.

Endpoint

GET /isw/payments/balance
Reference: PaymentsController.java:37-41

Use cases

Pre-payment validation

Verify sufficient funds before initiating payment transactions

Balance display

Show current available balance in your application UI

Reconciliation

Compare expected balance with actual balance during reconciliation

Low balance alerts

Monitor balance and trigger alerts when funds are running low

Implementation

The balance retrieval is implemented in PaymentsService.fetchBalance():
public String fetchBalance() throws Exception {
    String endpointUrl = Constants.ROOT_LINK + "sente/accountBalance";
    String request = endpointUrl 
        + "?terminalId=" + Constants.TERMINAL_ID 
        + "&requestReference=" + java.util.UUID.randomUUID();

    SystemResponse<KeyExchangeResponse> exchangeKeys = keyExchangeService.doKeyExchange();

    if(exchangeKeys.getResponseCode().equals(PhoenixResponseCodes.APPROVED.CODE)) {
        Map<String,String> headers = AuthUtils.generateInterswitchAuth(
            Constants.GET_REQUEST, 
            request, 
            "",
            exchangeKeys.getResponse().getAuthToken(),
            exchangeKeys.getResponse().getTerminalKey()
        );
        return HttpUtil.getHTTPRequest(request, headers);
    }
    else {
        return "Cannot Continue with balance Check,Key Exchange failed";
    }
}
Reference: PaymentsService.java:74-88

Request parameters

The balance endpoint requires no request body. Query parameters are automatically included:
terminalId
string
required
Your terminal ID (automatically added by the service)
requestReference
string
required
Unique identifier for this balance request (automatically generated using UUID)
The service automatically generates a unique request reference for each balance check using java.util.UUID.randomUUID().

Response structure

Success response

{
  "responseCode": "90000",
  "responseMessage": "TRANSACTION APPROVED",
  "terminalId": "00000001",
  "availableBalance": 1500000.00,
  "ledgerBalance": 1500000.00,
  "currencyCode": "UGX",
  "accountName": "Company Name",
  "requestReference": "a7f3e2c1-4b5d-6e7f-8a9b-0c1d2e3f4a5b"
}

Response fields

responseCode
string
Response code indicating success or failure. “90000” indicates success.
availableBalance
double
Current available balance that can be used for transactions
ledgerBalance
double
Total ledger balance including pending transactions
currencyCode
string
Currency code of the wallet (e.g., UGX, USD)
accountName
string
Name associated with the terminal account

Error response

{
  "responseCode": "90091",
  "responseMessage": "REMOTE SYSTEM TEMPORARILY UNAVAILABLE"
}

Code examples

Basic balance check

@Autowired
private PaymentsService paymentsService;

public double getCurrentBalance() {
    try {
        String response = paymentsService.fetchBalance();
        JSONObject json = new JSONObject(response);
        
        if ("90000".equals(json.getString("responseCode"))) {
            return json.getDouble("availableBalance");
        } else {
            throw new BalanceCheckException(
                "Failed to retrieve balance: " + json.getString("responseMessage")
            );
        }
    } catch (Exception e) {
        System.err.println("Balance check failed: " + e.getMessage());
        throw new BalanceCheckException(e);
    }
}

Validate sufficient balance

public boolean hasSufficientBalance(double requiredAmount) {
    try {
        double availableBalance = getCurrentBalance();
        return availableBalance >= requiredAmount;
    } catch (Exception e) {
        System.err.println("Cannot verify balance: " + e.getMessage());
        return false;
    }
}

Pre-payment balance check

public void processPaymentWithBalanceCheck(PaymentRequest request) throws Exception {
    double paymentAmount = request.getAmount();
    
    // Check balance first
    String balanceResponse = paymentsService.fetchBalance();
    JSONObject balanceJson = new JSONObject(balanceResponse);
    
    if (!"90000".equals(balanceJson.getString("responseCode"))) {
        throw new BalanceCheckException("Cannot verify balance");
    }
    
    double availableBalance = balanceJson.getDouble("availableBalance");
    
    if (availableBalance < paymentAmount) {
        throw new InsufficientFundsException(
            String.format("Insufficient balance. Available: %.2f, Required: %.2f",
                availableBalance, paymentAmount)
        );
    }
    
    // Proceed with payment
    String paymentResponse = paymentsService.makePayment(request);
    // Handle payment response...
}

Display balance information

public BalanceInfo getBalanceInfo() {
    try {
        String response = paymentsService.fetchBalance();
        JSONObject json = new JSONObject(response);
        
        if ("90000".equals(json.getString("responseCode"))) {
            BalanceInfo info = new BalanceInfo();
            info.setAvailableBalance(json.getDouble("availableBalance"));
            info.setLedgerBalance(json.getDouble("ledgerBalance"));
            info.setCurrencyCode(json.getString("currencyCode"));
            info.setAccountName(json.getString("accountName"));
            return info;
        } else {
            throw new BalanceCheckException(json.getString("responseMessage"));
        }
    } catch (Exception e) {
        throw new BalanceCheckException("Failed to retrieve balance", e);
    }
}

Using the REST endpoint

curl -X GET http://localhost:8081/isw/payments/balance
Reference: README.md:13

Best practices

Caching balance data

Don’t cache balance data for too longBalance can change rapidly due to ongoing transactions. Cache for a maximum of 1-2 minutes to avoid showing stale data.
private Double cachedBalance = null;
private Long cacheTimestamp = null;
private static final long CACHE_DURATION = 60000; // 1 minute

public double getBalanceWithCache() throws Exception {
    long now = System.currentTimeMillis();
    
    if (cachedBalance != null && 
        cacheTimestamp != null && 
        (now - cacheTimestamp) < CACHE_DURATION) {
        return cachedBalance;
    }
    
    // Refresh cache
    cachedBalance = getCurrentBalance();
    cacheTimestamp = now;
    return cachedBalance;
}

Low balance monitoring

Implement alerts for low balance conditions:
private static final double LOW_BALANCE_THRESHOLD = 100000.00;

public void checkAndAlertLowBalance() {
    try {
        double balance = getCurrentBalance();
        
        if (balance < LOW_BALANCE_THRESHOLD) {
            sendLowBalanceAlert(
                String.format("Wallet balance is low: %.2f UGX", balance)
            );
        }
    } catch (Exception e) {
        System.err.println("Failed to check balance: " + e.getMessage());
    }
}

Scheduled balance checks

Schedule periodic balance checks for monitoring:
@Scheduled(cron = "0 0 9,15 * * ?") // 9 AM and 3 PM daily
public void scheduledBalanceCheck() {
    try {
        String response = paymentsService.fetchBalance();
        JSONObject json = new JSONObject(response);
        
        if ("90000".equals(json.getString("responseCode"))) {
            double balance = json.getDouble("availableBalance");
            
            // Log balance
            logger.info("Current wallet balance: {} {}", 
                balance, json.getString("currencyCode"));
            
            // Check threshold
            checkAndAlertLowBalance();
            
            // Store for reporting
            saveBalanceHistory(balance);
        }
    } catch (Exception e) {
        logger.error("Scheduled balance check failed", e);
    }
}

Error handling

Implement comprehensive error handling:
public Double getBalanceWithRetry() {
    int maxRetries = 3;
    int delay = 2000; // 2 seconds
    
    for (int attempt = 1; attempt <= maxRetries; attempt++) {
        try {
            String response = paymentsService.fetchBalance();
            JSONObject json = new JSONObject(response);
            
            if ("90000".equals(json.getString("responseCode"))) {
                return json.getDouble("availableBalance");
            } else if ("90091".equals(json.getString("responseCode"))) {
                // System temporarily unavailable - retry
                if (attempt < maxRetries) {
                    Thread.sleep(delay * attempt);
                    continue;
                }
            } else {
                // Other error - don't retry
                throw new BalanceCheckException(
                    json.getString("responseMessage")
                );
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new BalanceCheckException("Interrupted during retry", e);
        } catch (Exception e) {
            if (attempt == maxRetries) {
                throw new BalanceCheckException(
                    "Failed after " + maxRetries + " attempts", e
                );
            }
        }
    }
    
    return null;
}

Balance vs ledger balance

Available balance is the amount you can currently use for transactions.Ledger balance includes pending transactions and may be higher than available balance.
Always use availableBalance when validating if sufficient funds exist for a new transaction:
if (availableBalance >= requiredAmount) {
    // Sufficient funds
} else {
    // Insufficient funds
}

Common error codes

Response CodeMessageAction
90000TRANSACTION APPROVEDBalance retrieved successfully
90091REMOTE SYSTEM TEMPORARILY UNAVAILABLERetry after a delay
90096AN ERROR OCCURREDCheck system logs and retry
90063AUTHORIZATION ERRORVerify credentials and terminal configuration
Reference: PhoenixResponseCodes.java:7-9

Integration with payment flow

Integrate balance checks into your payment workflow:
public String processPaymentWorkflow(PaymentRequest request) throws Exception {
    // Step 1: Check balance
    if (!hasSufficientBalance(request.getAmount())) {
        throw new InsufficientFundsException("Wallet balance too low");
    }
    
    // Step 2: Validate customer
    String validationResponse = paymentsService.validateCustomer(request);
    JSONObject validation = new JSONObject(validationResponse);
    if (!"90000".equals(validation.getString("responseCode"))) {
        throw new ValidationException("Customer validation failed");
    }
    
    // Step 3: Process payment
    String paymentResponse = paymentsService.makePayment(request);
    return paymentResponse;
}

Next steps

Process payments

Execute payment transactions after verifying balance

Payment operations

Return to payment operations overview

Build docs developers (and LLMs) love