Pay
Vipaso Pay SDK makes it easy to add both online and offline payment capabilities via BLE to your Android app with simple user authentication, payment methods, and transaction handling
Table of Contents
- Prerequisites
- Setup and Configuration
- Error Handling
- SDK Overview
- Managed Authentication (PayManagedAuthApi)
- Delegated Authentication (PayDelegatedAuthApi)
- User Management (PayUserApi)
- Payment Instruments (PayInstrumentApi)
- Payment Processing (PayPaymentApi)
Prerequisites
SDK Version Requirements
- Android Compile SDK: 34 (Your app App Compile SDK must be 34 or higher)
- Android Target SDK = 34
- Android Min SDK: 26 (Your app App Min SDK must be 34 or higher)
Required Permissions
The following permissions must be added to your app's AndroidManifest.xml
file:
<!-- BLE feature requirement -->
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<!-- Bluetooth permissions -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<!-- Location permissions (for Android 10 and below) -->
<uses-permission
android:name="android.permission.ACCESS_FINE_LOCATION"
android:maxSdkVersion="30" />
<uses-permission
android:name="android.permission.ACCESS_COARSE_LOCATION"
android:maxSdkVersion="30" />
<!-- Bluetooth permissions for Android 12+ -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission
android:name="android.permission.BLUETOOTH_ADVERTISE"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<!-- Network permission -->
<uses-permission android:name="android.permission.INTERNET" />
For Android 12 (API level 31) and above, you will need to request runtime permissions for BLUETOOTH_ADVERTISE
and BLUETOOTH_CONNECT
. For Android 11 and below, ACCESS_FINE_LOCATION
permission is required for BLE scanning. Make sure to properly request these permissions in your app before using the BLE payment functionality.
Setup and Configuration
Initialize the SDK
The recommended way is to initialize the Vipaso SDK using the VipasoSdkInitializer
singleton object. This will set up all necessary components and allow you to interact with the SDK features.
When initializing the SDK, you need to:
- First initialize the SDK with the appropriate mode
- Then set the configuration parameters
// Step 1: Initialize the SDK with the appropriate mode
VipasoSdkInitializer.initialize(context, VipasoSdkMode.Pay)
/*
Possible SDK modes:
- VipasoSdkMode.Pos: Pos mode (for merchants to request payments)
- VipasoSdkMode.Pay: Pay mode (for users to receive payments and pay)
- VipasoSdkMode.Full: Full mode (includes both Pos and Pay features)
*/
// Step 2: Create and set the SDK configuration
val sdkConfig = VipasoSdkConfig(
baseUrl = "https://your.base.path",
bleUuidService = UUID.fromString("your-service-uuid"),
emailSupport = "[email protected]", // Optional
timeoutPaymentStatusBackendPollingDuration = 60.seconds // Optional, defaults to 60 seconds
)
// Set the SDK configuration, you need to set this before using any of the SDK features
VipasoSdkInitializer.setSdkConfig(sdkConfig)
Accessing the SDK
The Vipaso Pay SDK uses Koin for internal dependency injection. Depending on your application's DI framework, you can access the SDK in one of the following ways:
Option 1: Using Dependency Injection (Koin)
As the SDK uses Koin for internal dependency injection, you can directly access SDK dependencies:
// Access VipasoPay directly from SDK's Koin container
val vipasoPay by SdkKoinProvider.koin.inject<VipasoPay>()
Option 2: Using Dependency Injection (Dagger/Hilt)
If your application uses Hilt/Dagger for dependency injection, you need to re-provide the SDK dependencies:
// Re-providing dependencies from Koin DI to Hilt DI framework
// since the SDK uses Koin internally
@Module
@InstallIn(SingletonComponent::class)
class VipasoPayModule {
@Provides
@Singleton
fun provideVipasoPay(): VipasoPay {
val vipasoPay by SdkKoinProvider.koin.inject<VipasoPay>()
return vipasoPay
}
}
Option 3: Without Dependency Injection
If your app doesn't use dependency injection, you can initialize the SDK directly:
// it's possible to initialize SDK directly
val vipasoPay = VipasoPayImpl()
Error Handling
When calling SDK methods, wrap them in try/catch blocks to handle exceptions properly. All SDK operations may throw appropriate exceptions when an unexpected error occurs. Implementing proper error handling ensures your application responds gracefully to network issues, BLE connection errors, or other errors.
try {
val user = vipasoPay.managedAuth.fetchUser()
// Process user data
} catch (e: Throwable) {
// Handle unexpected errors
}
SDK Overview
The Vipaso Pay SDK is structured around a main interface called VipasoPay
, which serves as the entry point to all SDK functionality. After initialization, you can access the main APIs through this interface:
// Obtain the VipasoPay instance through your preferred method
val vipasoPay: VipasoPay = ...
// Access the main APIs
val managedAuthApi: PayManagedAuthApi = vipasoPay.managedAuth
val delegatedAuthApi: PayDelegatedAuthApi = vipasoPay.delegatedAuth
val userApi: PayUserApi = vipasoPay.user
val instrumentApi: PayInstrumentApi = vipasoPay.instrument
val paymentApi: PayPaymentApi = vipasoPay.payment
Authentication APIs
The SDK provides two different authentication approaches:
- Managed Authentication: When your app wants to use Vipaso's authentication system and identity provider.
- Delegated Authentication: When your app uses its own authentication system and identity provider.
PayManagedAuthApi
Handles user authentication when using Vipaso's identity provider and account management:
- login() - Authenticate users with email and password
- startSignupFlow() - Begin user registration process
- verifyPhoneNumber() - Verify phone during signup with OTP
- finalizeSignupFlow() - Complete user registration
- startRecoveryFlow() - Begin account recovery process
- verifyRecoveryOtp() - Verify phone during recovery with OTP
- finalizeRecoveryFlow() - Complete recovery with new password
PayDelegatedAuthApi
Handles authentication when your app uses its own identity provider:
- establishAuthentication() - Connect your app's authentication system with Vipaso
PayUserApi
Manages user profile information, login state and user-specific features:
- getUserLoginState() - Observe user authentication state changes
- logout() - Deauthenticate current user
- fetchUser() - Get current user information
- fetchFeatureFlags() - Get feature flags available for the current user
PayInstrumentApi
Manages payment instruments like cards, MNO, and third-party instruments:
- fetchInstruments() - Get all available payment instruments
- fetchInstrument() - Get details for a specific instrument
- removeInstrument() - Delete a payment instrument
- createCardInstrument() - Add a new card payment method
- createMnoInstrument() - Add a mobile network operator payment method
- createThirdPartyInstrument() - Add an external payment provider
- preAuthorizeInstrument() - Pre-authorize funds on an instrument (Experimental)
- topUpInstrument() - Add funds to a payment instrument
- withdrawFromInstrument() - Transfer funds from an instrument
PayPaymentApi
Processes payments and maintains payment history:
- fetchPayments() - Get list of payment transactions
- fetchPayment() - Get details for a specific payment
- listenForBlePayments() - Listen for incoming payments via BLE
- acceptPayment() - Approve an incoming payment request
- cancelPayment() - Reject or cancel a payment operation
- stopBle() - Stop BLE and receiving payment requests
Managed Authentication (PayManagedAuthApi)
The PayManagedAuthApi
handles all authentication-related functionality when using Vipaso's identity provider, including user login, registration, and account recovery. Choose this approach when you want Vipaso to handle user authentication completely.
The PayManagedAuthApi
handles all authentication-related functionality when using Vipaso's identity provider, including user login, registration, and account recovery. Choose this approach when you want Vipaso to handle user authentication completely.
User Authentication
Login
Once a user has an account, logging in is straightforward. You pass the phone number or email as the identifier along with a password. The SDK will store the session token securely, and the auth state listeners will be notified of the change.
// Request: Login with email/phone and password
val loginRequest = LoginRequest(
userIdentifer = "[email protected]", // Can be email or phone number
password = "secure_password"
)
vipasoPay.managedAuth.login(loginRequest)
// You can observe login state changes via user.getUserLoginState()
Account Recovery
Password recovery consists of three steps, each requiring a network call.
Start Recovery Flow
First, initiate the recovery flow with the user's phone number. This will trigger an OTP code to be sent to that number.
// Request: Begin account recovery
val recoveryRequest = StartRecoveryRequest(phoneNumber = "+1234567890")
val recoveryResponse = vipasoPay.managedAuth.startRecoveryFlow(recoveryRequest)
// Response: Contains the flow ID needed for subsequent steps
StartRecoveryResponse(
flowId = "recovery-flow-123"
)
Verify Recovery OTP
Next, verify the OTP code received by the user. Send the flow ID from the previous step along with the OTP code.
// Request: Verify OTP code during recovery
val recoveryOtpResponse = vipasoPay.managedAuth.verifyRecoveryOtp(
flowId = "recovery-flow-123",
otpCode = "123456"
)
// Response: Contains settings flow ID and session token needed for password update
RecoveryOtpResponse(
settingsFlowId = "settings-flow-abc",
sessionToken = "session-token-xyz"
)
Finalize Recovery Flow
Finally, complete the recovery process by updating the password. Use the settings flow ID and session token obtained in the previous step.
// Request: Complete recovery with new password
val passwordRequest = UpdatePasswordRequest(
settingFlowId = "settings-flow-abc",
sessionToken = "session-token-xyz",
password = "new_secure_password"
)
vipasoPay.managedAuth.finalizeRecoveryFlow(passwordRequest)
// The login state will be updated if recovery is successful
// You can observe login state changes via getUserLoginState()
User Registration
The registration flow consists of three steps, each requiring a network call.
Start Signup Flow
First, you need to create a new registration flow with a phone number. This will trigger an OTP code to be sent to the user's phone number via SMS or WhatsApp.
// Request: Begin user registration with phone number
val signupRequest = StartSignupRequest(phoneNumber = "+1234567890")
val signupResponse = vipasoPay.managedAuth.startSignupFlow(signupRequest)
// Response: Contains the flow ID needed for subsequent steps
StartSignupResponse(
flowId = "signup-flow-456"
)
Verify Signup OTP
Next, verify the phone number by sending the flow ID received in the previous step along with the OTP code that the user received.
// Request: Verify phone number during signup using OTP
val verifyRequest = VerifyPhoneNumberRequest(
flowId = "signup-flow-456",
otp = "123456" // The OTP code sent to the user's phone
)
val verifyResponse = vipasoPay.managedAuth.verifyPhoneNumber(verifyRequest)
// Response: Contains the flow ID for the final step
VerifyPhoneNumberResponse(
flowId = "signup-flow-456"
)
Finish Signup Flow
Lastly, complete the signup by sending all the user data collected through the flow. The SDK will store the session token securely and the auth state listeners will be notified about the successful authentication.
// Request: Complete the signup process with user details
val finishRequest = FinishSignupRequest(
flowId = "signup-flow-456",
password = "secure_password",
email = "[email protected]",
name = "John Doe", // Deprecated, use firstName and lastName instead
firstName = "John",
lastName = "Doe",
phoneNumber = "+1234567890"
)
val signupResult = vipasoPay.managedAuth.finalizeSignupFlow(finishRequest)
// Response: Contains the flow ID
FinishSignupResponse(
flowId = "signup-flow-456"
)
// The auth state listener will be notified about the successful authentication
// You can observe login state changes via user.getUserLoginState()
User Information
Fetch User
// Request: Get current user details
val user = vipasoPay.user.fetchUser()
// Response: User profile information
VipasoUser(
id = "user123",
email = "[email protected]",
phone = "+1234567890",
firstName = "John",
lastName = "Doe"
)
Delegated Authentication (PayDelegatedAuthApi)
The PayDelegatedAuthApi
enables integration with your own authentication system. Choose this approach when your app already has user accounts and you want to maintain your existing identity management while using Vipaso's payment features.
Establish Authentication
// Request: Establish authentication between your own identity provider and Vipaso SDK
vipasoPay.delegatedAuth.establishAuthentication(
// The unique identifier for the user in your system
userIdentifier = "user-123",
// A callback that receives a JWK (provided by Vipaso SDK) as input and outputs a string (you get from your backend)
connect = { jwk ->
// 1. Send the JWK to a dedicated backend endpoint provided on your domain
// 2. And then return the output string received from your backend
}
)
// Once this call returns successfully then you can use all the SDK features
User Management (PayUserApi)
The PayUserApi
manages user profile information, login state tracking, and user-specific features.
Logout
Simply calling the logout function will remove the stored session token and notify the auth state listeners of the change.
// Request: Logout current user
vipasoPay.user.logout()
// You can observe login state changes via getUserLoginState()
Fetch Feature Flags
// Request: Get feature flags for the current user
val featureFlags = vipasoPay.user.fetchFeatureFlags()
// Response: Set of feature flags with their states
Set<VipasoFeatureFlagWithState>(
VipasoFeatureFlagWithState(
featureFlag = "feature_name_1",
isEnabled = true
),
VipasoFeatureFlagWithState(
featureFlag = "feature_name_2",
isEnabled = false
)
)
Get User Login State
// Request: Observe the user's login state
vipasoPay.user.getUserLoginState()
.collect { loginState ->
when (loginState) {
LoginState.LoggedIn -> {
// User is logged in, proceed with app functionality
}
LoginState.NotLoggedIn -> {
// User is not logged in, show login screen
}
}
}
Payment Instruments (PayInstrumentApi)
The PayInstrumentApi
manages all payment instruments including cards, MNO (Mobile Network Operator), and third-party payment options.
Fetch Instruments
// Request: Get all available payment instruments
val instruments = vipasoPay.instrument.fetchInstruments()
// Response: List of payment instruments
InstrumentResponse(
instruments = [
VipasoInstrument(
id = "instrument_id",
type = InstrumentType.CARD,
isDefault = true,
details = CardDetails(
last4 = "1111",
cardType = "visa",
expiryMonth = 12,
expiryYear = 2025
)
),
VipasoInstrument(
id = "instrument_id_2",
type = InstrumentType.MNO,
isDefault = false,
details = MnoDetails(
provider = "Provider Name",
phoneNumber = "+1234567890"
)
)
]
)
Fetch Instrument
// Request: Get details for a specific instrument
val instrument = vipasoPay.instrument.fetchInstrument("instrument_id")
// Response: Detailed instrument information
VipasoInstrument(
id = "instrument_id",
type = InstrumentType.CARD,
isDefault = true,
details = CardDetails(
last4 = "1111",
cardType = "visa",
expiryMonth = 12,
expiryYear = 2025
)
)
/*
Possible InstrumentType values:
- CARD: Credit or debit card instrument
- BANK_ACCOUNT: Direct bank account instrument
- MNO: Mobile Network Operator payment instrument
*/
Remove Instrument
// Request: Delete a payment instrument
vipasoPay.instrument.removeInstrument("instrument_id")
Create Card Instrument
Add a new card payment method to the user's account. The card will be validated and stored securely:
// Request: Add a new card payment method
val cardRequest = CreateCardInstrumentRequest(
cardNumber = "4111111111111111",
expiryMonth = 12,
expiryYear = 2025,
cvv = "123",
cardholderName = "John Doe"
)
val cardResponse = vipasoPay.instrument.createCardInstrument(cardRequest)
// Response: Created card instrument details
CardInstrumentResponse(
instrumentId = "card-123",
last4 = "1111",
cardType = "visa",
expiryMonth = 12,
expiryYear = 2025,
cardholderName = "John Doe",
isDefault = true
)
/*
Possible VipasoInstrumentStatus values:
- IN_PROGRESS: Instrument creation is being processed
- VERIFIED: Instrument has been successfully verified and is ready for use
- FAILED: Instrument creation or verification failed
*/
Create MNO Instrument
Add a mobile network operator payment method to the user's account:
// Request: Add a mobile network operator payment method
val mnoRequest = CreateMnoInstrumentRequest(
phoneNumber = "+1234567890",
provider = "Provider Name"
)
val mnoResponse = vipasoPay.instrument.createMnoInstrument(mnoRequest)
// Response: Created MNO instrument details
MnoInstrumentResponse(
instrumentId = "mno-456",
phoneNumber = "+1234567890",
provider = "Provider Name",
isDefault = false,
verificationRequired = true,
verificationUrl = "https://verify.example.com/mno/456"
)
Create Third-Party Instrument
Create an instrument with an existing third-party ID from your own system:
// Request: Add an external payment provider
val thirdPartyRequest = CreateThirdPartyInstrumentRequest(
provider = "Provider Name",
accountId = "account_id"
)
val thirdPartyResponse = vipasoPay.instrument.createThirdPartyInstrument(thirdPartyRequest)
// Response: Created third-party instrument details
ThirdPartyInstrumentResponse(
instrumentId = "tp-789",
provider = "PayPal",
accountId = "[email protected]",
isDefault = false,
redirectUrl = "https://connect.example.com/thirdparty/789"
)
Pre-Authorize Instrument (Experimental)
Certain instruments can be pre-authorized with an amount of money to enable users to pay in offline mode. This is an EXPERIMENTAL functionality.
// Request: Pre-authorize funds on an instrument
val preAuthRequest = PreAuthorizationRequest(
instrumentId = "instrument_id",
amount = 100.0,
currency = "USD"
)
val preAuth = vipasoPay.instrument.preAuthorizeInstrument(preAuthRequest)
// Response: Pre-authorization results
VipasoPreAuthorization(
id = "preauth-123",
instrumentId = "instrument_id",
amount = 30.0,
currency = "USD",
expiryTime = 1623498765432
)
Top Up Instrument
Top up allows funds to be transferred from a mobile phone number to an instrument. This results in a response containing a URL which points to the web flow start page for the top-up process.
// Request: Add funds to a payment instrument
val topUpRequest = TopUpRequest(
instrumentId = "instrument_id",
amount = 50.0,
currency = "USD"
)
val topUpResponse = vipasoPay.instrument.topUpInstrument(topUpRequest)
// Response: Contains URL to complete the top-up process in a web flow
TopUpResponse(
webFlowUrl = "https://pay.vipaso.io/topup/flow/abc123"
)
Withdraw From Instrument
Withdrawal allows funds to be transferred from an instrument to a supplied phone number. The response contains an ID and a status.
// Request: Transfer funds from an instrument
val withdrawalRequest = WithdrawalRequest(
instrumentId = "instrument_id",
amount = 25.0,
currency = "USD"
)
val withdrawalResponse = vipasoPay.instrument.withdrawFromInstrument(withdrawalRequest)
// Response: Withdrawal status information
WithdrawalResponse(
id = "withdrawal-789",
status = WithdrawalStatus.IN_PROGRESS // Other possible values: INITIATED, COMPLETED, CANCELLED, FAILED
)
/*
Possible WithdrawalStatus values:
- INITIATED: Withdrawal request has been created but processing hasn't started
- IN_PROGRESS: Withdrawal is currently being processed
- COMPLETED: Withdrawal has been successfully completed
- CANCELLED: Withdrawal was cancelled by the user or system
- FAILED: Withdrawal processing failed due to an error
*/
Payment Processing (PayPaymentApi)
The PayPaymentApi
handles all payment-related operations including initiating payments, checking payment status, and processing BLE payments.
Payment History
Fetch Payments
Retrieve a paginated list of payment transactions with optional filtering by status:
// Request: Get list of payment transactions
val payments = vipasoPay.payment.fetchPayments(
page = 0,
status = VipasoPaymentStatus.COMPLETED
)
// Response: List of payment transactions
FetchPaymentsResponse(
payments = [
VipasoPayment(
paymentId = "payment-123",
amount = 25.50,
currency = "USD",
unifiedStatus = VipasoPaymentStatus.COMPLETED,
timestamp = 1623412345678,
instrumentId = "card-123",
instrumentType = "CARD",
description = "Coffee and sandwich",
lastUpdate = "2025-06-03T09:25:48Z",
merchant = VipasoMerchant(
merchantId = "merchant-456",
name = "Coffee Shop"
),
consumer = VipasoConsumer(
id = "user-123",
name = "John Doe"
)
),
VipasoPayment(
paymentId = "payment-124",
amount = 75.00,
currency = "USD",
unifiedStatus = VipasoPaymentStatus.PENDING,
timestamp = 1623412345678,
instrumentId = "mno-456",
instrumentType = "MNO",
description = "Phone accessories",
lastUpdate = "2025-06-03T09:24:12Z",
merchant = VipasoMerchant(
merchantId = "merchant-789",
name = "Electronics Store"
),
consumer = VipasoConsumer(
id = "user-123",
name = "John Doe"
)
)
],
totalCount = 15,
hasMore = true
)
/*
Possible VipasoPaymentStatus values:
- INITIATED: Payment has been created but processing hasn't started
- IN_PROGRESS: Payment is currently being processed
- COMPLETED: Payment has been successfully completed and funds transferred
- FAILED: Payment processing failed due to an error
- CANCELLED: Payment was cancelled by the user, merchant, or system
*/
Fetch Payment Details
Fetch the complete details of a specific payment by its ID:
// Request: Get details for a specific payment
val paymentDetails = vipasoPay.payment.fetchPayment(
request = FetchPaymentDetailsRequest(paymentId = "payment_id")
)
// Response: Detailed payment information
FetchPaymentDetailsResponse(
payment = VipasoPayment(
paymentId = "payment-123",
amount = 25.50,
currency = "USD",
unifiedStatus = VipasoPaymentStatus.COMPLETED,
timestamp = 1623412345678,
instrumentId = "card-123",
instrumentType = "CARD",
description = "Coffee and sandwich",
lastUpdate = "2025-06-03T09:25:48Z",
merchant = VipasoMerchant(
merchantId = "merchant-456",
name = "Coffee Shop"
),
consumer = VipasoConsumer(
id = "user-123",
name = "John Doe"
)
)
)
/*
Possible VipasoPaymentStatus values:
- INITIATED: Payment has been created but processing hasn't started
- IN_PROGRESS: Payment is currently being processed
- COMPLETED: Payment has been successfully completed and funds transferred
- FAILED: Payment processing failed due to an error
- CANCELLED: Payment was cancelled by the user, merchant, or system
*/
BLE Payment
The BLE Payment functionality allows receiving payments and payment events from Vipaso PoS Devices. The SDK provides a Flow-based approach to listen for and process BLE payment events.
Listen for incoming payments via BLE
Start detecting and receiving payment requests via Bluetooth Low Energy from Vipaso PoS Devices. This returns a Flow that emits payment state changes as they occur:
// Request: Start detecting Bluetooth payment requests from Vipaso PoS Devices
val blePaymentsFlow = vipasoPay.payment.listenForBlePayments()
// Response: Flow of VipasoWalletPaymentState values
// Collect and handle payment states:
scope.launch {
blePaymentsFlow.collect { state ->
when (state) {
is VipasoWalletPaymentState.ReceivedPaymentRequest -> {
// Request to pay received from terminal
val amount = state.amount
val currency = state.currency
val merchantId = state.merchantId
val merchantName = state.merchantName
// You can accept or decline the payment request
}
is VipasoWalletPaymentState.PaymentSuccessful -> {
// Payment was successful, show confirmation
}
is VipasoWalletPaymentState.PaymentCancelled -> {
// Payment was cancelled
}
is VipasoWalletPaymentState.AnotherUserPaid -> {
// Another user paid instead
}
is VipasoWalletPaymentState.PaymentFailed -> {
// Payment failed, show error message
}
}
}
}
Accept Payment
When an incoming payment request arrives via BLE, users can decide if they accept it. In case the user accepts the payment, the following method sends the acceptance to the PoS Terminal:
// Request: Accept a payment from a BLE payment request
vipasoPay.payment.acceptPayment(
paymentId = "payment-id-from-request",
instrumentId = "selected-instrument-id", // ID of the payment instrument to use
amount = 50.00,
tip = 5.00, // Optional
currency = "USD"
)
// The payment result will be delivered through the listenForBlePayments() flow
// as a PaymentSuccessful, PaymentFailed, or other state
Cancel Payment
In case the user doesn't accept a payment, the following method has to be called to notify the PoS Terminal that the payment is not accepted:
// Request: Reject or cancel a payment operation
vipasoPay.payment.cancelPayment("payment_id")
// The payment state will be updated in the BLE payment flow
// You'll receive a PaymentCancelled state in the listenForBlePayments flow
Stop BLE
When your app no longer needs to listen for BLE payments (for example, when the user navigates away from the payment screen) or when closing the app, call this method to clean up resources and stop the BLE detection:
// Request: Stop listening for BLE payments
vipasoPay.payment.stopBle()
// After calling this, you'll no longer receive payment requests or states
// You can call listenForBlePayments() again to start listening for new payments
Updated 7 days ago