NetPOS supports cash-out services, allowing merchants to provide cash withdrawal services to customers. This feature enables merchants to act as agent banking points where customers can withdraw cash using their debit cards.
Overview
Cash-out services transform the POS terminal into an ATM-like service point where customers can withdraw cash from their bank accounts using their debit cards.
Cash-out transactions require EMV card reading capabilities and proper merchant authorization as an agent banking provider.
Cash-Out Flow
Initiate Cash-Out
Merchant selects cash-out service and enters withdrawal amount
Card Authentication
Customer inserts or taps their debit card on the POS terminal
PIN Entry
Customer enters their card PIN for authorization
Process Transaction
System processes the cash withdrawal request through the payment gateway
Dispense Cash
Upon approval, merchant dispenses cash to the customer
Receipt Generation
System generates transaction receipt for both merchant and customer
Transaction Response Model
Cash-out transactions use the CashOutResponse model:
@Root (strict = false , name = "transferResponse" )
data class CashOutResponse @JvmOverloads constructor (
@field : Element ( name = " description ")
var description: String = "" ,
@field : Element ( name = " field39 ")
var field39: String = "A3" ,
@field : Element ( name = " authId ", required = false )
var authId: String = "" ,
@field : Path (" hostEmvData ")
@field : Element ( name = " AmountAuthorized ", required = false )
var amountAuthorized: Long = 0L ,
@field : Path (" hostEmvData ")
@field : Element ( name = " AmountOther ", required = false )
var AmountOther: Long = 0L ,
@field : Path (" hostEmvData ")
@field : Element ( name = " atc ", required = false )
var atc: String = "" ,
@field : Path (" hostEmvData ")
@field : Element ( name = " iad ", required = false )
var iad: String = "" ,
@field : Path (" hostEmvData ")
@field : Element ( name = " rc ", required = false )
var rc: Int = 0 ,
@field : Element ( name = " referenceNumber ", required = false )
var referenceNumber: String = "" ,
@field : Element ( name = " transactionChannelName ", required = false )
var transactionChannelName: String = "" ,
@field : Element ( name = " wasReceived ", required = false )
var wasReceived: Boolean = false ,
@field : Element ( name = " wasSent ", required = false )
var wasSent: Boolean = false
)
Response Fields
Field Type Description descriptionString Transaction description/status message field39String Response code (e.g., “00” for approved, “A3” for default) authIdString Authorization ID from the bank amountAuthorizedLong Authorized withdrawal amount in minor units AmountOtherLong Additional amount (e.g., fees) atcString Application Transaction Counter iadString Issuer Application Data rcInt Response code referenceNumberString Unique transaction reference number transactionChannelNameString Channel used for transaction wasReceivedBoolean Indicates if response was received wasSentBoolean Indicates if request was sent
Transaction Response Conversion
The CashOutResponse is converted to TransactionResponse for storage:
fun CashOutResponse . toTransactionResponse (
stan: String ,
cardData: CardData ,
transactionTime: Long ,
iswParameters: IswParameters ,
amount: Long ,
interswitchThreshold: Long = 0L ,
errorMessage: String ? = null ,
reqRRN: String = ""
) = TransactionResponse (). also {
it.amount = amount
it.RRN = if ( this .referenceNumber. isEmpty ()) reqRRN else this .referenceNumber
it.responseCode = this .field39
it.authCode = this .authId
it.STAN = stan
it.echoData = iswParameters.remark
it.maskedPan = StringUtils. overlay (cardData.pan, "xxxxxx" , 6 , 12 )
it.cardExpiry = cardData.expiryDate
it.cardLabel = ""
it.transactionTimeInMillis = transactionTime
it.transactionType = TransactionType.PURCHASE
it.terminalId = iswParameters.terminalId
it.merchantId = iswParameters.merchantId
it.transmissionDateTime = SimpleDateFormat ( "MMddhhmmss" , Locale. getDefault ())
. format (transactionTime)
it.localTime_12 = SimpleDateFormat ( "hhmmss" , Locale. getDefault ())
. format (transactionTime)
it.localDate_13 = SimpleDateFormat ( "MMdd" , Locale. getDefault ())
. format (transactionTime)
it.accountType = IsoAccountType.DEFAULT_UNSPECIFIED
it.source = PosMode.ISW
it.errorMessage = errorMessage
it.interSwitchThreshold = interswitchThreshold
}
TransactionResponse Fields
it.maskedPan = StringUtils. overlay (cardData.pan, "xxxxxx" , 6 , 12 )
it.cardExpiry = cardData.expiryDate
it.cardLabel = ""
maskedPan - Card number with middle digits masked (e.g., 5399xxxxxx1234)
cardExpiry - Card expiration date from EMV chip
cardLabel - Card scheme label (Visa, Mastercard, etc.)
it.transactionTimeInMillis = transactionTime
it.transmissionDateTime = SimpleDateFormat ( "MMddhhmmss" , Locale. getDefault ())
. format (transactionTime)
it.localTime_12 = SimpleDateFormat ( "hhmmss" , Locale. getDefault ())
. format (transactionTime)
it.localDate_13 = SimpleDateFormat ( "MMdd" , Locale. getDefault ())
. format (transactionTime)
transactionTimeInMillis - Transaction timestamp in milliseconds
transmissionDateTime - Formatted datetime (MMddhhmmss)
localTime_12 - Time in hhmmss format
localDate_13 - Date in MMdd format
Transaction Identifiers
it.STAN = stan
it.RRN = if ( this .referenceNumber. isEmpty ()) reqRRN else this .referenceNumber
it.authCode = this .authId
STAN - System Trace Audit Number (unique transaction ID)
RRN - Retrieval Reference Number
authCode - Authorization code from issuing bank
Card Data Processing
Cash-out transactions require reading card data from the EMV chip:
val cardData = CardData (
pan = "5399XXXXXXXX1234" ,
expiryDate = "12/25" ,
cardholderName = "JOHN DOE" ,
track2Data = "..."
)
val maskedPan = StringUtils. overlay (
cardData.pan,
"xxxxxx" ,
6 , // Start position
12 // End position
)
// Result: 5399xxxxxx1234
ISW Parameters
Interswitch parameters required for cash-out:
data class IswParameters (
val terminalId: String ,
val merchantId: String ,
val merchantCategoryCode: String ,
val merchantNameAndLocation: String ,
val remark: String
)
Parameter Sources
Parameter Description Source terminalIdPOS terminal ID User configuration merchantIdMerchant identifier User configuration merchantCategoryCodeMCC code for agent banking Configuration merchantNameAndLocationMerchant details User profile remarkTransaction remark System generated
Transaction Types
Cash-out is processed as a PURCHASE transaction:
it.transactionType = TransactionType.PURCHASE
Available Transaction Types
PURCHASE - Standard purchase/cash-out
REFUND - Refund transaction
CASH_ADVANCE - Cash advance on credit cards
PRE_AUTHORIZATION - Pre-auth hold
Account Types
it.accountType = IsoAccountType.DEFAULT_UNSPECIFIED
Supported Account Types
DEFAULT_UNSPECIFIED - Default account type
SAVINGS - Savings account
CURRENT - Current/checking account
CREDIT - Credit card account
POS Mode
Transactions are processed through Interswitch (ISW) gateway.
Response Codes
Success Codes
Decline Codes
Error Codes
00 - Approved/successful
10 - Partial approval (amount less than requested)
51 - Insufficient funds
55 - Incorrect PIN
91 - Issuer unavailable
A3 - Default/pending
06 - Error
12 - Invalid transaction
30 - Format error
Transaction Storage
Completed transactions are stored with:
val transactionResponse = cashOutResponse. toTransactionResponse (
stan = generateSTAN (),
cardData = cardData,
transactionTime = System. currentTimeMillis (),
iswParameters = getIswParameters (),
amount = withdrawalAmount,
interswitchThreshold = threshold,
errorMessage = null ,
reqRRN = requestRRN
)
// Save to database
transactionDao. insert (transactionResponse)
Cash-out receipts include:
Transaction Details
Transaction type (Cash Withdrawal)
Amount
Date and time
Reference number (RRN)
Card Information
Masked PAN
Card type
Authorization code
Response message
Merchant Details
Merchant name
Terminal ID
Merchant ID
Location
Status
Approval status
Response code
STAN
Receipt number
Security Considerations
Critical Security Requirements:
Cash must only be dispensed after receiving approved response (field39 = “00”)
Verify authorization code is present and valid
Ensure card PIN is entered securely on POS device
Store transaction records securely for reconciliation
Implement daily cash-out limits as per banking regulations
Best Practices
Pre-Transaction Verification
Verify merchant has sufficient cash before initiating cash-out
Card Reading
Use EMV chip reading for enhanced security (avoid magnetic stripe)
PIN Entry
Ensure customer enters PIN on secure POS keypad, never on merchant device
Response Validation
Check response code is “00” before dispensing cash
Receipt Printing
Print receipt immediately after approved transaction
Cash Dispensing
Count cash in front of customer before handing over
Record Keeping
Store transaction records for audit and reconciliation
Error Handling
Error: Customer account has insufficient balanceAction: Inform customer and offer to retry with lower amount
Error: Customer entered wrong PINAction: Allow customer to retry (max 3 attempts before card lock)
Error: No response from payment gatewayAction: DO NOT dispense cash. Perform transaction reversal or inquiry
Error: Bank approved less than requested amountAction: Dispense approved amount or cancel and retry
Compliance Requirements
Merchants providing cash-out services must:
Be registered as authorized agent banking providers
Maintain adequate cash float for daily operations
Implement daily cash-out limits per customer
Keep detailed transaction records for regulatory compliance
Report suspicious transactions as per AML/CFT regulations
Transaction History View and manage cash-out transaction records
Card Payments Learn about card payment processing