App-to-app integration
Connect your Android POS app on the same device as the Peach Payments Payment App using the Intent API library (com.peach:intent_api).
For payment flows (sale, refund, void, recovery), see Terminal integration flows.
Integration modes
| Mode | When | How |
|---|---|---|
| Native Android | Kotlin or Java POS app | Use builders in com.peach.intentApi.builder |
| Web POS in WebView | React or other web UI in your Kotlin shell | Bridge WebView → Kotlin → Intent API; or use window.FinimoPay in Peach Payments web-wrapper pattern |
Amounts are always Long in minor currency units (cents). Sale amount must be > 0.
Installation
Maven repository
Add the Peach Payments GitLab package registry to your project settings.gradle - no access token required:
repositories {
maven {
url 'https://gitlab.com/api/v4/projects/61399867/packages/maven'
}
}Dependency
dependencies {
implementation 'com.peach:intent_api:2.0.8'
}Pin the version Peach Payments confirms for your integration. Refund and void require 2.0.6+.
Architecture
Your POS app
│
├─ Sale / Refund / Void / TransactionLookup builders
│
├─ [binder available] ──► AIDL to Payment App
│
└─ [no binder] ──► CommunicationActivity ──► Payment App
│
▼
ResultObject JSON ──► your listener callback (UI thread)The Payment App package follows com.finimo.paymentapp (variant suffixes per build).
Kotlin quick start
Sale.Builder(context)
.amount(1000L) // R 10.00
.disableReceiptingOnOutcome(true)
.setExternalPosData(mapOf("merchantTransactionId" to orderId))
.setListener(object : SaleTransactionListener {
override fun alertSaleTransactionResponse(response: PosTransactionSummary) {
val success = response.isApproved &&
(response.transactionType == PosTransactionType.SALE ||
response.transactionType == PosTransactionType.SALE_WITH_CASHBACK)
}
override fun alertError(error: IntentError) { /* see Intent error codes */ }
})
.startTransaction()Implement SaleTransactionListener, RefundTransactionListener, VoidTransactionListener, or TransactionLookupListener depending on the operation.
Java quick start
new Sale.Builder(context)
.amount(1000L)
.setExternalPosData(Collections.singletonMap("merchantTransactionId", orderId))
.setListener(new SaleTransactionListener() {
@Override
public void alertSaleTransactionResponse(PosTransactionSummary response) { }
@Override
public void alertError(IntentError error) { }
})
.startTransaction();Web POS (Kotlin shell + WebView)
Supported pattern for React or other web clients:
- Your Kotlin app hosts a
WebViewwith your POS URL. - Expose a
@JavascriptInterface(or replicate the web-wrapperPaymentInterfaceorFinimoPaybridge). - On payment request from JavaScript, call Intent API builders from Kotlin - do not call the Payment App directly from JavaScript.
In Peach Payments' web-wrapper sample, the bridge object is window.FinimoPay. Older samples may reference PaymentInterface.
| JavaScript method | Maps to |
|---|---|
FinimoPay.sale(amount, posData) | Sale builder |
FinimoPay.refund(amount, transactionId) | Refund builder |
FinimoPay.void(transactionId) | Void builder |
FinimoPay.lastTransaction() | Transaction lookup |
Your page implements callbacks (for example, onSaleComplete, onError) registered by the bridge.
Operations
| Operation | Builder entry | Notes |
|---|---|---|
| Sale | Sale.Builder → amount, startTransaction | Optional disableReceiptingOnOutcome, redirectText |
| Sale with cashback | SaleWithCashback.Builder | amount + cashbackAmount |
| Refund | Refund.Builder → refundTransaction(amount, transactionId) | transactionId = original sale UUID; use the same terminal as the sale |
| Void | Void.Builder → performVoid(transactionId) | Known issue - use a refund instead |
| Last transaction | TransactionLookup.Builder → lastTransaction | Most recent transaction where the customer tapped, inserted, or swiped a card |
| Search | TransactionLookup.Builder → searchTransaction(params) | Filter by amount, time, RRN, and so on - use when lastTransaction is not enough |
| Prepare next | PrepareNextTransaction.Builder | Pre-warm Payment App (optional) |
Refund and void availability
The original sale and refund must be processed on the same terminal. The Payment App asks for a supervisor PIN and a refund reason. Multiple partial refunds are supported for up to 180 days, provided that their total does not exceed the original sale amount.
Limit access to the supervisor PIN to reduce refund fraud risk.
Intent-triggered voids have a known issue. Use a refund instead until Peach Payments resolves it.
Builder options (common)
| Method | Purpose |
|---|---|
setExternalPosData(map) | Pass merchantTransactionId and custom fields |
disableReceiptingOnOutcome(true) | Auto-return to POS after ~10s on outcome screen |
redirectText(text) | Custom label on outcome close button |
setListener(...) | Register operation-specific callback |
Lookup flags on results
| Field | Use |
|---|---|
isRefundable | Show refund action in POS |
isVoidable | Show void action in POS |
lastTransaction() vs searchTransaction
lastTransaction() vs searchTransactionlastTransaction()- returns only the most recent transaction where the customer tapped, inserted, or swiped a card. Attempts where no card details were provided are not returned.searchTransaction- use for broader recovery by amount, date range, RRN, and other supported filters. You cannot search byposData.merchantTransactionId.
If lookup returns an error or no matching successful result, always treat the payment as unsuccessful in your POS - do not mark the order paid.
Callbacks and response models
| Listener method | When |
|---|---|
alertSaleTransactionResponse | Sale completed |
alertRefundTransactionResponse | Refund completed |
alertVoidResponse | Void completed (VoidResponse) |
alertTransactionLookupResponse | Lookup completed |
alertError | Error before or during handoff |
PosTransactionSummary (sale/refund) includes transactionId, transactionType, isApproved, transactionResult, posData, rrn, amount.
See Intent API data models for full field tables.
Error codes
See Intent error codes for all IntentErrorCode values and descriptions.
Next steps
- Terminal integration flows: end-to-end sale, refund, void, and recovery flows.
- Test your integration: Mock Payments App and UAT terminal testing.
- Request a UAT account and install the UAT Payment App before terminal testing.
Updated 20 days ago