Links

Payment Initiation

Good to know: Payment Initiation is responsible for handling bank payments.
Firstly, you will need to integrate kevin. API and fetch payment ID. Instructions on how to do it can be found here:

Basic flow

Customise payment flow by tweaking our configuration:
// initialize configuration with paymentId fetched from the API
let configuration = KevinPaymentSessionConfiguration.Builder(paymentId: paymentId)
.setPreselectedCountry(.lithuania)
.setCountryFilter([.lithuania, .latvia, .estonia])
.setDisableCountrySelection(false)
.setPreselectedBank("SOME_BANK_ID")
.setSkipBankSelection(false)
.setSkipAuthentication(false)
.build()
Implement KevinPaymentSessionDelegate protocol. Make sure that in onKevinPaymentInitiationStarted you present returned UINavigationController:
protocol KevinPaymentSessionDelegate: AnyObject {
func onKevinPaymentInitiationStarted(controller: UINavigationController)
func onKevinPaymentCanceled(error: Error?)
func onKevinPaymentSucceeded(paymentId: String)
}
Call KevinPaymentSession and listen to delegate:
KevinPaymentSession.shared.delegate = self
try KevinPaymentSession.shared.initiatePayment(
configuration: configuration
)

UIKit

class BankPaymentViewController: UIViewController {
func initiatePayment() {
// fetch your payment id from kevin. API
let paymentID = await apiService.fetchBankPaymentID()
do {
let configuration = try KevinPaymentSessionConfiguration.Builder(paymentId: paymentID)
.build()
​
// Set the delegate
KevinPaymentSession.shared.delegate = self
KevinPaymentSession.shared.initiatePayment(configuration: configuration)
} catch {
// handle session initiation error
}
}
}
​
extension BankPaymentViewController: KevinPaymentSessionDelegate {
func onKevinPaymentInitiationStarted(controller: UINavigationController) {
present(controller, animated: true)
}
​
func onKevinPaymentCanceled(error: Error?) {
// handle payment failure and cancellation
}
​
func onKevinPaymentSucceeded(paymentId: String, status: KevinPaymentStatus) {
// handle payment success
}
}

SwiftUI

Library is built on UIKit, however it can be easily used within SwiftUI.
Firstly, create representable for kevin. UIViewController:
import SwiftUI
​
struct KevinViewControllerRepresentable: UIViewControllerRepresentable {
let controller: UIViewController
func makeUIViewController(context: Context) -> some UIViewController {
return controller
}
func updateUIViewController(
_ uiViewController: UIViewControllerType,
context: Context
) { }
}
Define your view from which you will be showing representable:
import Kevin
import SwiftUI
​
struct SampleView: View {
​
@ObservedObject var viewModel: SampleViewModel
​
var body: some View {
VStack(spacing: 20) {
Spacer()
Button {
viewModel.invokeBankPaymentInitiationSession()
} label: {
Text("Make Bank Payment")
}.buttonStyle(MainButtonStyle())
.sheet(isPresented: $viewModel.viewState.openKevin, content: {
if let controller = viewModel.kevinController {
KevinViewControllerRepresentable(controller: controller)
.presentation(canDismissSheet: false)
}
})
Spacer()
}
.padding(20)
}
}
Define your ViewModel which will subscribe to KevinPaymentSessionDelegate and invoke the SDK:
import UIKit
import Kevin
​
class SampleViewModel: ObservableObject, KevinPaymentSessionDelegate {
@Published var viewState = SampleViewState()
var kevinController: UIViewController? = nil
private let apiClient = ApiClient()
func invokeBankPaymentInitiationSession() {
apiClient.initializeBankPayment().done { state in
do {
KevinPaymentSession.shared.delegate = self
try KevinPaymentSession.shared.initiatePayment(
configuration: KevinPaymentSessionConfiguration.Builder(
paymentId: state.id
)
.setPreselectedCountry(.lithuania)
.setSkipBankSelection(false)
.build()
)
} catch {
// do something
}
}.catch { error in
// do something
}
}
//MARK: KevinPaymentSessionDelegate
func onKevinPaymentInitiationStarted(controller: UINavigationController) {
self.kevinController = controller
self.viewState = MainViewState(openKevin: true)
}
func onKevinPaymentCanceled(error: Error?) {
// notify user if error has been returned
}
func onKevinPaymentSucceeded(paymentId: String) {
// notify user
}
}
​

Customise session configuration

KevinPaymentSessionConfiguration can be configured with following properties:
  • setPreselectedCountry - allows to set a default country to be selected in the bank selection screen. If this parameter is not specified, the selection will be based on the SIM card information. In case the SIM card information is not available, the SDK will use the device locale. If the SIM card information and device locale are unavailable, the SDK will select the first country from the country filter (or fall back to the first bank on the list).
  • setPreselectedBank - allows to specify a default bank that will be preselected in the bank selection screen.
  • setCountryFilter - allows only certain countries to be supported.
  • setBankFilter - allows to filter banks and show only selected ones to the user. It requires a list of bank IDs that should be shown.
  • setDisableCountrySelection - if set to true, country selection will be disabled, and only preselected country banks will be available to choose from.
  • setSkipBankSelection - if set to true country, and bank selection step will be skipped, and the user will be redirected to the bank SCA immediately.
  • setSkipAuthentication - allows users to skip the SCA bank step and proceed directly to the payment confirmation. Bank payment needs to be initialised with an account access token. See reference here.
​
Example:
KevinPaymentSession.shared.initiatePayment(
configuration: KevinPaymentSessionConfiguration.Builder(
paymentId: state.id
)
.setPreselectedCountry(.lithuania)
.setCountryFilter([.lithuania, .latvia, .estonia])
.setPreselectedBank("SOME_BANK_ID")
.build()
)