
Unified type-safe API integrating Google Pay and Apple Pay, with reactive capability detection, Compose UI payment components, serializable tokens, robust error handling and thread-safe, production-ready state management.
Quickstart • Installation • Samples • Documentation •
A Kotlin Multiplatform payment library with Compose Multiplatform UI components for Google Pay and Apple Pay across Android, iOS, and Web. One API, shared types, reactive availability detection, and platform-native payment buttons.
| Platform | Google Pay | Apple Pay | Compose UI |
|---|---|---|---|
| Android | ✅ | ❌ | ✅ |
| iOS | ❌ | ✅ | ✅ |
| Web (JS) | ✅ | ✅ | ✅ |
| WASM | ✅ | ✅ | ✅ |
Apple Pay on Web works natively in Safari. On other browsers (Chrome, Firefox, Edge), the Apple Pay JS SDK enables a QR code flow where users scan with their iPhone to pay (iOS 18+).
// Mobile (Android / iOS)
val manager = rememberMobilePaymentManager(config)
val launcher = rememberNativePaymentLauncher { result ->
when (result) {
is PaymentResult.Success -> handleSuccess(result.token)
is PaymentResult.Error -> handleError(result)
is PaymentResult.Cancelled -> { /* no action */ }
}
}
PaymentButton(enabled = isReady, onClick = { launcher.launch("10.00") })
// Web (JS / WASM)
val manager = rememberWebPaymentManager(config)
val applePay = rememberApplePayWebLauncher { result -> /* handle */ }
val googlePay = rememberGooglePayWebLauncher { result -> /* handle */ }
Button(onClick = { applePay.launch("10.00") }) { Text("Apple Pay") }Ensure Maven Central is in your repositories, then add dependencies:
# libs.versions.toml
[versions]
kpayment = "0.1.0"
[libraries]
kpayment-core = { module = "com.kttipay:kpayment-core", version.ref = "kpayment" }
kpayment-mobile = { module = "com.kttipay:kpayment-mobile", version.ref = "kpayment" }
kpayment-web = { module = "com.kttipay:kpayment-web", version.ref = "kpayment" }kotlin {
sourceSets {
commonMain.dependencies { implementation(libs.kpayment.core) }
androidMain.dependencies { implementation(libs.kpayment.mobile) }
iosMain.dependencies { implementation(libs.kpayment.mobile) }
jsMain.dependencies { implementation(libs.kpayment.web) }
wasmJsMain.dependencies { implementation(libs.kpayment.web) }
}
}Android: No additional setup. Google Play Services Wallet is included.
iOS: Add "Apple Pay" capability in Xcode and configure your merchant ID.
Web: For cross-browser Apple Pay, add the JS SDK to your HTML <head>:
<script src="https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js"
crossorigin="anonymous"></script>// Google Pay
val googlePay = GooglePayConfig(
merchantId = "YOUR_MERCHANT_ID",
merchantName = "Your Store",
gateway = GatewayConfig.Stripe(publishableKey = "pk_live_...")
)See Google Pay gateway configuration for FatZebra, Braintree, Adyen, and other gateways.
// Apple Pay (Mobile)
val applePayMobile = ApplePayMobileConfig(
merchantId = "merchant.com.yourcompany.app",
base = ApplePayBaseConfig(merchantName = "Your Store")
)
// Apple Pay (Web)
val applePayWeb = ApplePayWebConfig(
base = ApplePayBaseConfig(merchantName = "Your Store"),
merchantValidationEndpoint = "https://example.com/apple-pay/validate",
baseUrl = "https://example.com",
domain = "example.com",
enableJsSdk = true // cross-browser QR code flow (default)
)// Reactive (recommended)
val isReady by manager.observeAvailability(PaymentProvider.GooglePay)
.collectAsState(initial = false)
Button(enabled = isReady, onClick = { launcher.launch("10.00") }) { Text("Pay") }
// Explicit check
val capabilities = manager.checkCapabilities()
when (capabilities.googlePay) {
CapabilityStatus.Ready -> { /* show button */ }
CapabilityStatus.Checking -> { /* loading */ }
is CapabilityStatus.Error -> { /* handle error */ }
else -> { /* not available */ }
}when (result) {
is PaymentResult.Success -> sendTokenToBackend(result.token)
is PaymentResult.Error -> {
when (result.reason) {
PaymentErrorReason.NetworkError -> showNetworkError()
PaymentErrorReason.NotAvailable -> showAlternativePayment()
PaymentErrorReason.AlreadyInProgress -> { /* disable button via launcher.isProcessing */ }
else -> showGenericError(result.message)
}
}
is PaymentResult.Cancelled -> { /* no action needed */ }
}| Reason | Suggested Action |
|---|---|
NetworkError |
Check network, retry |
NotAvailable |
Show alternative payment |
AlreadyInProgress |
Disable button via launcher.isProcessing
|
DeveloperError |
Fix configuration |
Timeout |
Retry after delay |
SignInRequired |
Prompt sign-in |
KPayment/
├── payment-core/ Shared interfaces, models, config, result types
├── payment-mobile/ Android (Google Pay) + iOS (Apple Pay) implementations
└── payment-web/ Web JS/WASM (Google Pay + Apple Pay) implementations
Each module has its own README with platform-specific details:
payment-core/README.mdpayment-mobile/README.mdpayment-web/README.md — includes Apple Pay JS SDK button options and cross-browser QR flowKPaymentLogger.enabled = true
KPaymentLogger.callback = object : KPaymentLogCallback {
override fun onLog(event: LogEvent) { println("[${event.tag}] ${event.message}") }
}./gradlew sampleMobile:installDebug # Android
cd iosApp && pod install && open iosApp.xcworkspace # iOS
./gradlew sampleWeb:wasmJsBrowserDevelopmentRun # Web./gradlew check)Report a bug | Development setup
Apache 2.0. See LICENSE.
Built with ❤️ using Kotlin Multiplatform
Quickstart • Installation • Samples • Documentation •
A Kotlin Multiplatform payment library with Compose Multiplatform UI components for Google Pay and Apple Pay across Android, iOS, and Web. One API, shared types, reactive availability detection, and platform-native payment buttons.
| Platform | Google Pay | Apple Pay | Compose UI |
|---|---|---|---|
| Android | ✅ | ❌ | ✅ |
| iOS | ❌ | ✅ | ✅ |
| Web (JS) | ✅ | ✅ | ✅ |
| WASM | ✅ | ✅ | ✅ |
Apple Pay on Web works natively in Safari. On other browsers (Chrome, Firefox, Edge), the Apple Pay JS SDK enables a QR code flow where users scan with their iPhone to pay (iOS 18+).
// Mobile (Android / iOS)
val manager = rememberMobilePaymentManager(config)
val launcher = rememberNativePaymentLauncher { result ->
when (result) {
is PaymentResult.Success -> handleSuccess(result.token)
is PaymentResult.Error -> handleError(result)
is PaymentResult.Cancelled -> { /* no action */ }
}
}
PaymentButton(enabled = isReady, onClick = { launcher.launch("10.00") })
// Web (JS / WASM)
val manager = rememberWebPaymentManager(config)
val applePay = rememberApplePayWebLauncher { result -> /* handle */ }
val googlePay = rememberGooglePayWebLauncher { result -> /* handle */ }
Button(onClick = { applePay.launch("10.00") }) { Text("Apple Pay") }Ensure Maven Central is in your repositories, then add dependencies:
# libs.versions.toml
[versions]
kpayment = "0.1.0"
[libraries]
kpayment-core = { module = "com.kttipay:kpayment-core", version.ref = "kpayment" }
kpayment-mobile = { module = "com.kttipay:kpayment-mobile", version.ref = "kpayment" }
kpayment-web = { module = "com.kttipay:kpayment-web", version.ref = "kpayment" }kotlin {
sourceSets {
commonMain.dependencies { implementation(libs.kpayment.core) }
androidMain.dependencies { implementation(libs.kpayment.mobile) }
iosMain.dependencies { implementation(libs.kpayment.mobile) }
jsMain.dependencies { implementation(libs.kpayment.web) }
wasmJsMain.dependencies { implementation(libs.kpayment.web) }
}
}Android: No additional setup. Google Play Services Wallet is included.
iOS: Add "Apple Pay" capability in Xcode and configure your merchant ID.
Web: For cross-browser Apple Pay, add the JS SDK to your HTML <head>:
<script src="https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js"
crossorigin="anonymous"></script>// Google Pay
val googlePay = GooglePayConfig(
merchantId = "YOUR_MERCHANT_ID",
merchantName = "Your Store",
gateway = GatewayConfig.Stripe(publishableKey = "pk_live_...")
)See Google Pay gateway configuration for FatZebra, Braintree, Adyen, and other gateways.
// Apple Pay (Mobile)
val applePayMobile = ApplePayMobileConfig(
merchantId = "merchant.com.yourcompany.app",
base = ApplePayBaseConfig(merchantName = "Your Store")
)
// Apple Pay (Web)
val applePayWeb = ApplePayWebConfig(
base = ApplePayBaseConfig(merchantName = "Your Store"),
merchantValidationEndpoint = "https://example.com/apple-pay/validate",
baseUrl = "https://example.com",
domain = "example.com",
enableJsSdk = true // cross-browser QR code flow (default)
)// Reactive (recommended)
val isReady by manager.observeAvailability(PaymentProvider.GooglePay)
.collectAsState(initial = false)
Button(enabled = isReady, onClick = { launcher.launch("10.00") }) { Text("Pay") }
// Explicit check
val capabilities = manager.checkCapabilities()
when (capabilities.googlePay) {
CapabilityStatus.Ready -> { /* show button */ }
CapabilityStatus.Checking -> { /* loading */ }
is CapabilityStatus.Error -> { /* handle error */ }
else -> { /* not available */ }
}when (result) {
is PaymentResult.Success -> sendTokenToBackend(result.token)
is PaymentResult.Error -> {
when (result.reason) {
PaymentErrorReason.NetworkError -> showNetworkError()
PaymentErrorReason.NotAvailable -> showAlternativePayment()
PaymentErrorReason.AlreadyInProgress -> { /* disable button via launcher.isProcessing */ }
else -> showGenericError(result.message)
}
}
is PaymentResult.Cancelled -> { /* no action needed */ }
}| Reason | Suggested Action |
|---|---|
NetworkError |
Check network, retry |
NotAvailable |
Show alternative payment |
AlreadyInProgress |
Disable button via launcher.isProcessing
|
DeveloperError |
Fix configuration |
Timeout |
Retry after delay |
SignInRequired |
Prompt sign-in |
KPayment/
├── payment-core/ Shared interfaces, models, config, result types
├── payment-mobile/ Android (Google Pay) + iOS (Apple Pay) implementations
└── payment-web/ Web JS/WASM (Google Pay + Apple Pay) implementations
Each module has its own README with platform-specific details:
payment-core/README.mdpayment-mobile/README.mdpayment-web/README.md — includes Apple Pay JS SDK button options and cross-browser QR flowKPaymentLogger.enabled = true
KPaymentLogger.callback = object : KPaymentLogCallback {
override fun onLog(event: LogEvent) { println("[${event.tag}] ${event.message}") }
}./gradlew sampleMobile:installDebug # Android
cd iosApp && pod install && open iosApp.xcworkspace # iOS
./gradlew sampleWeb:wasmJsBrowserDevelopmentRun # Web./gradlew check)Report a bug | Development setup
Apache 2.0. See LICENSE.
Built with ❤️ using Kotlin Multiplatform