The identiPay POS (Point of Sale) app is an Android application for merchants to accept privacy-preserving payments. It creates payment proposals, displays QR codes, and monitors transaction settlement in real-time.
data class ProposalRequest( val items: List<ProposalItem>, val amount: ProposalAmount, val deliverables: ProposalDeliverables, val constraints: ProposalConstraints? = null, val expiresInSeconds: Int,)data class ProposalItem( val name: String, val quantity: Int, val unitPrice: String, val currency: String,)data class ProposalAmount( val value: String, val currency: String,)data class ProposalDeliverables( val receipt: Boolean,)data class ProposalConstraints( val ageGate: Int, // Minimum age requirement)
data class ProposalResponse( val transactionId: String, val intentHash: String, val qrDataUrl: String? = null, val uri: String, val expiresAt: String,)
data class CartState( val items: List<CartItem> = emptyList(),) { val total: Double get() = items.sumOf { it.product.price * it.quantity }}data class CartItem( val product: Product, val quantity: Int,)
2
Create Proposal
Generate payment proposal with optional age gate:
val proposal = IdentipayApi.createProposal( items = cartItems, total = cartTotal, ageGate = if (requiresAgeCheck) 21 else null,)
3
Display QR Code
Show QR code and NFC prompt:
val qrBitmap = BitmapFactory.decodeByteArray( Base64.decode(proposal.qrDataUrl, Base64.DEFAULT), 0, Base64.decode(proposal.qrDataUrl, Base64.DEFAULT).size,)Image( bitmap = qrBitmap.asImageBitmap(), contentDescription = "Payment QR Code",)
4
Monitor Settlement
Connect to WebSocket for real-time status updates:
val wsUrl = "wss://${IdentipayApi.backendHost}/ws/transactions/${proposal.transactionId}"webSocket.onMessage { message -> val update = json.decodeFromString<SettlementUpdate>(message) when (update.status) { "pending" -> showWaitingState() "settled" -> showSuccessState(update.txDigest) "expired" -> showExpiredState() "cancelled" -> showCancelledState() }}
5
Print Receipt
Once settled, print receipt if printer is available:
if (printerService.isBound()) { val receipt = formatReceipt( items = cartItems, total = cartTotal, txDigest = settlement.txDigest, timestamp = System.currentTimeMillis(), ) printerService.print(receipt)}
data class Product( val id: String, val name: String, val price: Double, val currency: String = "USDC", val imageRes: Int? = null, val category: String, val ageRestricted: Boolean = false, val minimumAge: Int? = null,)
The wallet app automatically generates a zero-knowledge proof of age without revealing the exact date of birth.
Age-restricted sales require the customer’s wallet to support ZK age proofs. The transaction will fail if the customer is underage or cannot generate the proof.