Hosted Payment Page
The Hosted Payment Page provides a unified payment UI that presents all supported payment methods in a single flow. It's the recommended integration — one setup covers Google Pay, Instant Bank Transfer, and Pay by Card, and payabl. manages the method selection UI for you.
| Order Screen | Hosted Payment Page |
|---|---|
![]() | ![]() |
Flow: user taps Pay → Hosted Payment Page opens → user selects a payment method → result is returned via PBLPaymentResult.
Prerequisites
- The SDK is added to your project — see Android SDK.
- Your backend can create a session via
/mobile/init— see Setup Your Server. - Each payment method you enable in the checkout has its own setup — see below.
Payment method setup
The Hosted Payment Page gives you one integration for the payment UI, but each payment method you enable still requires its own configuration. Complete the setup for every method you plan to offer:
Pay by Card — works out of the box, no additional setup.
Google Pay — requires one-time registration with Google and payabl. before it appears in the checkout:
- Your app is published on Google Play, your Business profile is complete, and your Google Merchant ID is shared with payabl.
- The Google Wallet API
meta-datais enabled in yourAndroidManifest.xml. - Your
/mobile/initrequest includes thecountryparameter.
→ Full setup: Google Pay
Instant Bank Transfer — requires deep link handling so the customer returns to your app after authorizing in their bank:
- Your
/mobile/initrequest includes the redirect URLs (url_success,url_failed,url_return,notification_url) andapp_schema. - Your
AndroidManifest.xmlincludes an intent filter matching those redirect URLs. - Your Activity forwards the returning deep link to the SDK via
handlePaymentCallback— in bothonNewIntentandonCreate.
→ Full setup: Instant Bank Transfer
If a payment method's setup is incomplete, it may not appear in the checkout or may fail when selected — while the other methods continue to work. If a method is missing or failing for your customers, check its setup page above first.
Integration
1. Fetch session configuration
Request a session from your backend and build a PBLConfiguration. Create a new session for every payment attempt.
private suspend fun fetchSessionConfiguration(): PBLConfiguration {
val response = apiClient.initPayment()
return PBLConfiguration(
sessionId = response.sessionId,
ephemeralKey = response.ephemeralKey,
userId = "user_id_from_app",
environment = PBLEnvironment.SANDBOX // use PBLEnvironment.PRODUCTION when going live
)
}
Saved cardsThe SDK can securely save a customer's card and offer it for reuse on their next payment. To enable this, pass a stable, unique
userIdfor the customer inPBLConfiguration— the same value every time that customer pays.Saved cards are scoped to the
userId, so the value must consistently identify the same person across sessions (for example, your internal customer ID). If you pass a different, random, or emptyuserIdbetween payments, previously saved cards won't be shown.Never use a value that changes per session (such as the
sessionId) or personally identifying data (such as an email address) as theuserId.
2. Launch the Hosted Payment Page
Initialize the SDK only when the user starts a payment, then start the flow.
private var payablSDK: PayablSDK? = null
private fun placeOrderWithSessionInit() {
lifecycleScope.launch {
val configuration = fetchSessionConfiguration()
payablSDK = PayablSDK.init(configuration)
payablSDK?.start(supportFragmentManager) { result ->
handlePaymentResult(result)
}
}
}
If Instant Bank Transfer is enabled, your Activity must also forward the returning deep link to the SDK — see Handle the deep link return.
3. Handle the result
The SDK returns a PBLPaymentResult. Handle all three cases, and release the SDK reference afterwards.
private fun handlePaymentResult(result: PBLPaymentResult) {
when (result) {
is PBLPaymentResult.Completed -> {
// Payment successful — update order status
}
is PBLPaymentResult.Canceled -> {
// User cancelled the payment
}
is PBLPaymentResult.Failed -> {
// Payment failed — inspect result for the error code
}
}
payablSDK = null
}
For Instant Bank Transfer, the authoritative transaction status is confirmed server-to-server via thenotification_urlwebhook — reconcile against your backend before fulfilling the order rather than relying on the client result alone.
Best practices
Do:
- Create a new session for each payment attempt.
- Initialize
PayablSDKonly when the user starts a payment. - Release
payablSDKafter receiving a result. - Pass a stable, unique
userIdper customer if you want saved cards to work.
Don't:
- Reuse sessions across multiple payments.
- Initialize the SDK at app startup.
- Share sessions between users.
- Use a changing or shared value for
userId— it breaks saved cards and can mix customers' saved cards.
Testing
Use the sandbox environment (PBLEnvironment.SANDBOX) throughout development. To smoke-test a card payment, use this success card (expiry: any future date; CVV: any 3 digits):
| Card network | Card number | Expected result |
|---|---|---|
| VISA | 4149011500000147 | PBLPaymentResult.Completed |
For the complete set of test cards, decline scenarios, Google Pay test setup, and bank simulator values across all payment methods, see Testing.
Common issues
| Issue | Cause & resolution |
|---|---|
| Instant Bank Transfer doesn't return to the app | Deep linking isn't configured, the redirect URLs / app_schema are missing from /mobile/init, or the deep link isn't forwarded to the SDK. See Instant Bank Transfer. |
| Google Pay not shown in the checkout | Google Pay registration incomplete (Merchant ID not configured with payabl.), Wallet meta-data missing from the manifest, country missing from /mobile/init, or Google Pay isn't available on the device. See Google Pay. |
| Saved card not appearing for a returning customer | A different, empty, or changing userId was passed. Use the same stable userId for the customer on every payment. |
| Session error on launch | The session was reused, expired, or belongs to a different user. Create a fresh session per attempt. |
When something goes wrong, see Error Handling & Troubleshooting.


