Welcome to the PAYONE Commerce Platform Client iOS SDK for the PAYONE Commerce Platform. This SDK provides everything a client needs to easily complete payments using Credit or Debit Card, PAYONE Buy Now Pay Later (BNPL) and Apple Pay.
- Supported Languages and iOS Version
- Features
- Installation
- Usage
- Demonstration Projects
- Contributing
- Releasing the library
- License
The SDK supports Swift and Objective-C. For Objective-C the Bridge Module is needed. For Swift only the main module is needed.
In order to use the SDK you need to have at least iOS 15.
- Creditcard Tokenizer: Securely tokenize credit and debit card information.
- Fingerprint Tokenizer: Generate unique tokens for device fingerprinting.
- Apple Pay Session Integration: Seamlessly integrate Apple Pay into your payment workflow.
To integrate using Apple's Swift package manager, you have two options.
Add the following as a dependency to your Package.swift
:
.package(url: "https://https://github.com/PAYONE-GmbH/PCP-client-iOS-SDK.git", .upToNextMajor(from: "1.0.1"))
and then specify "PCPClient"
as a dependency of the Target in which you wish to use PCPClient.
Here's an example PackageDescription
:
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyPackage",
targets: ["MyPackage"]),
],
dependencies: [
.package(url: "https://github.com/PAYONE-GmbH/PCP-client-iOS-SDK.git", .upToNextMajor(from: "1.0.1"))
],
targets: [
.target(
name: "MyPackage",
dependencies: ["PCPClient"])
]
)
Select File
-> Add Package Dependencies...
. In the upcoming dialog paste the URL of this repository.
https://github.com/PAYONE-GmbH/PCP-client-iOS-SDK
Specify the version you want to use and click on 'Add Package'. This will pop up a dialog to chose which package products should be added to your target.
For Swift add PCPClient
to your target and select None
in the Add to target
dropdown for PCPClientBridge
.
For Objective-C add both package products to your target.
Finally, click again on 'Add Package'.
Add the following entry to your Podfile:
Swift
pod 'PCPClient'
Objective-C
pod 'PCPClient/PCPClientBridge'
Then run pod install
.
Don't forget to import the module(s) in every file you'd like to use PCPClient.
Swift
import PCPClient
Objective-C
@import PCPClient;
Note
When using SPM for the integration in an Objective-C project, you will also need the following import: @import PCPClientBridge;
. If you did the integration via CocoaPods, simply importing PCPClient will be enough.
The Credit Card Tokenizer is an essential component for handling payments on the PAYONE Commerce Platform. It securely collects and processes credit or debit card information to generate a paymentProcessingToken
, which is required for the Server-SDK to complete the payment process. Without this token, the server cannot perform the transaction. The tokenizer ensures that sensitive card details are handled securely and is PCI DSS (Payment Card Industry Data Security Standard) compliant.
To integrate the Creditcard Tokenizer feature into your application, follow these steps:
The Creditcard tokenizer injects code and PCI DSS conform input fields into a webpage. To assure this process works, you need to setup the correct containers and submit button.
<div id="cardpanInput"></div>
<div id="cardcvc2Input"></div>
<div id="cardExpireMonthInput"></div>
<div id="cardExpireYearInput"></div>
<button id="submit">Submit</button>
For a more sophisticated example, see this creditcard-tokenizer-example.html.
Swift
import PCPClient
Objective-C
@import PCPClient;
@import PCPClientBridge;
For SwiftUI use the CreditcardTokenizerView
.
CreditcardTokenizerView(
tokenizerUrl: URL(...),
request: CCTokenizerRequest(...),
supportedCardTypes: [...],
config: CreditcardTokenizerConfig(...)
)
For UIKit use the CreditcardTokenizerViewController
.
Swift
CreditcardTokenizerViewController(
tokenizerUrl: URL(...),
request: CCTokenizerRequest(...),
supportedCardTypes: [...],
config: CreditcardTokenizerConfig(...)
)
Objective-C
CreditcardTokenizerViewController *viewController = [
[CreditcardTokenizerViewController alloc]
initWithTokenizerUrl:[URL ...]
request:[CCTokenizerRequest...]
supportedCardTypes:@[...]
config:[CreditcardTokenizerConfigWrapper ...]
];
This is the URL where your HTML code can be found and this should include a valid HTML with the later specified fields and submit button.
Example:
URL(string: "https://github.com")!
Caution
Do not use local HTML since this won't work. The scripts that are used need a valid origin to send updates to, Therefore, it's currently a limitation that the HTML must be hosted.
The CCTokenizerRequest
object includes several configuration keys and settings. These are your AID, MID, Portal ID, PMI Portal Key and lastly the environment to run your code against (test or production).
Example:
CCTokenizerRequest(
mid: "123",
aid: "456",
portalId: "789",
environment: .test,
pmiPortalKey: "a1b2"
)
A String
array of supported card types. You should use the SupportedCardType
enum and it's identifier property to receive valid values.
Example:
[SupportedCardType.visa.identifier, SupportedCardType.mastercard.identifier]
The config including the different required fields, the callback(s), certain CSS styles, submit button ID, and the used language.
Important
For Objective-C you must use the CreditcardTokenizerConfigWrapper
since Swift completion handlers are not supported by Objective-C.
Swift Example:
CreditcardTokenizerConfig(
cardPan: Field(
selector: "cardpan",
style: "font-size: 14px; border: 1px solid #000;",
type: "input",
size: nil,
maxlength: nil,
length: nil,
iframe: nil
),
cardCvc2: Field(
selector: "cardcvc2",
style: "font-size: 14px; border: 1px solid #000;",
type: "password",
size: "4",
maxlength: "4",
length: [
"V": 3,
"M": 3
],
iframe: nil
),
cardExpireMonth: Field(
selector: "cardexpiremonth",
style: "font-size: 14px; width: 30px; border: solid 1px #000; height: 22px;",
type: "text",
size: "2",
maxlength: "2",
length: nil,
iframe: [
"width": "40px"
]
),
cardExpireYear: Field(
selector: "cardexpireyear",
style: nil,
type: "text",
size: nil,
maxlength: nil,
length: nil,
iframe: [
"width": "50px"
]
),
defaultStyles: [
"input": "font-size: 1em; border: 1px solid #000; width: 175px;",
"select": "font-size: 1em; border: 1px solid #000;",
"iframe": "height: 22px, width: 180px"
],
language: .german,
error: "error",
submitButtonId: "submit",
creditCardCheckCallback: { result in
switch result {
case let .success(response):
print(response)
case let .failure(error):
print("\(error.localizedDescription)")
}
}
)
Objective-C Example:
CreditcardTokenizerConfigWrapper *config = [
[CreditcardTokenizerConfigWrapper alloc]
initWithCardPan:[
[Field alloc]
initWithSelector:@"cardpan"
style:@"font-size: 14px; border: 1px solid #000;"
type:@"input"
size:NULL
maxlength:NULL
length:NULL
iframe:NULL
]
cardCvc2:[
[Field alloc]
initWithSelector:@"cardcvc2"
style:@"font-size: 14px; border: 1px solid #000;"
type:@"password"
size:@"4"
maxlength:@"4"
length:@{@"V": @3, @"M": @4}
iframe:NULL
]
cardExpireMonth:[
[Field alloc]
initWithSelector:@"cardexpiremonth"
style:@"font-size: 14px; width: 30px; border: solid 1px #000; height: 22px;"
type:@"text"
size:@"2"
maxlength:@"2"
length:NULL
iframe:@{@"width": @"40px"}
]
cardExpireYear:[
[Field alloc]
initWithSelector:@"cardexpireyear"
style:NULL
type:@"text"
size:NULL
maxlength:NULL
length:NULL
iframe:@{@"width": @"50px"}
]
defaultStyles:@{
@"input": @"font-size: 1em; border: 1px solid #000; width: 175px;",
@"select": @"font-size: 1em; border: 1px solid #000;",
@"iframe": @"height: 22px, width: 180px"
}
language:PayoneLanguageGerman
error:@"error"
submitButtonId:@"submit"
success:^(CCTokenizerResponse *response) {
NSLog(@"%@", response);
}
failure:^(enum CCTokenizerError error) {
NSLog(@"%@", [NSString stringWithFormat:@"%ld", (long)error]);
}
];
Defines the various input fields for credit card details.
Property | Type | Description |
---|---|---|
cardpan |
Field |
Configuration for the card number field. |
cardcvc2 |
Field |
Configuration for the card CVC2 field. |
cardexpiremonth |
Field |
Configuration for the card expiration month field. |
cardexpireyear |
Field |
Configuration for the card expiration year field. |
-
selector:
String
The CSS selector for the input element. -
element:
String
(optional)
The actual DOM element if not using a selector. -
size:
String
(optional)
The size attribute for the input element. -
maxlength:
String
(optional)
The maximum length of input allowed. -
length:
[String: Int]
Specifies the length for various card types (e.g.,[V: 3, M: 3, A: 4, J: 0 ]
). -
type:
String
The type attribute for the input element (e.g.,text
,password
). -
style:
String
(optional)
CSS styles applied to the input element. -
iframe:
[String: String]
Dimensions for the iframe if used (pass only width and height properties).
Property | Type | Description |
---|---|---|
language |
PayoneLanguage |
The language for the SDK (.german or .english for now). |
submitButtonId |
String |
HTML ID of the submit button. |
error |
String |
HTML ID of the div-container where error messages should be displayed. |
creditCardCheckCallback |
@escaping ((Result<CCTokenizerResponse, CCTokenizerError>) -> Void) |
Callback function for credit card check responses (Swift only). |
success |
@escaping (CCTokenizerResponse) -> Void |
Callback function for credit card check success (Objective-C Wrapper only). |
success |
@escaping (CCTokenizerError) -> Void |
Callback function for credit card check failure (Objective-C Wrapper only). |
This will heavily depend on your the platform and navigation technique your are using.
To detect and prevent fraud at an early stage for the secured payment methods, the Fingerprint Tokenizer is an essential component for handling PAYONE Buy Now, Pay Later (BNPL) payment methods on the PAYONE Commerce Platform. During the checkout process, it securely collects three different IDs to generate a snippetToken in the format <partner_id>_<merchant_id>_<session_id>
. This token must be sent from your server via the API parameter paymentMethodSpecificInput.customerDevice.deviceToken
. Without this token, the server cannot perform the transaction. The tokenizer sends these IDs via a code snippet to Payla for later server-to-Payla authorization, ensuring the necessary device information is captured to facilitate secure and accurate payment processing.
To integrate the Fingerprint Tokenizer feature into your application, follow these steps:
Swift
import PCPClient
Objective-C
@import PCPClient;
@import PCPClientBridge;
Create an instance with the payla partner ID, partner merchant ID and the environment (test or production).
Swift Example:
private let fingerprintTokenizer = FingerprintTokenizer(
paylaPartnerId: "YOUR_PARTNER_ID",
partnerMerchantId: "YOUR_MERCHANT_ID",
environment: .test
)
Objective-C Example:
self.tokenizerWrapper = [[FingerprintTokenizerWrapper alloc]
initWithPaylaPartnerId:@"YOUR_PARTNER_ID"
partnerMerchantId:@"YOUR_MERCHANT_ID"
environment:PCPEnvironmentTest sessionId:nil
];
In order to retrieve the snippet token you call the following method:
Swift Example:
fingerprintTokenizer.getSnippetToken { result in
switch result {
case let .success(token):
print(token)
case let .failure(error):
print(error.localizedDescription)
}
}
Objective-C Example:
[self.tokenizerWrapper getSnippetTokenWithSuccess:^(NSString *token) {
NSLog(@"token: %@", token);
} failure:^(enum FingerprintErrorWrapper error) {
NSLog(@"%@", [NSString stringWithFormat:@"%ld", (long)error]);
}
];
This snippet token is automatically generated when the FingerprintTokenizer
instance is created and is also stored by Payla for payment verification. You need to send this snippet token to your server so that it can be included in the payment request. Add the token to the property paymentMethodSpecificInput.customerDevice.deviceToken
.
For further information see: https://docs.payone.com/pcp/commerce-platform-payment-methods/payone-bnpl/payone-secured-invoice
This section guides you through integrating Apple Pay into your iOS app using the pcp-client-ios-sdk
. The integration involves handling the Apple Pay session.
There are some steps to perform before your app can handle Apple Pay. Follow the guidelines in the following resources:
Make sure that your server is set up and your environment is configured correctly according to the Apple Developer documentation. Follow the guidelines in the following resources:
Swift
import PCPClient
Objective-C
@import PCPClient;
@import PCPClientBridge;
The ApplePayHandler
expects a processPaymentServerUrl
which will be used to process the payment to your server.
Swift
private let applePayHandler = ApplePayHandler(processPaymentServerUrl: url)
Objective-C
self.applePayHandler = [[ApplePayHandler alloc] initWithProcessPaymentServerUrl:url];
Add a button to initiate the Apple Pay payment. You can use the method supportsApplePay
to check whether Apple Pay is supported on the device and then conditionally display the button.
SwiftUI Example:
@State private var shouldShowApplePay = false
...
VStack {
if shouldShowApplePay {
ApplePayButton()
.onTapGesture {
startPayment()
}
.frame(height: 30)
}
}
.onAppear {
shouldShowApplePay = applePayHandler.supportsApplePay()
}
Objective-C Example:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
if ([self.applePayHandler supportsApplePay]) {
PKPaymentButton *applePayButton = [PKPaymentButton buttonWithType: PKPaymentButtonTypePlain style:PKPaymentButtonStyleBlack];
[self.view addSubview:applePayButton];
[applePayButton addTarget:self action:@selector(startApplePay:) forControlEvents:UIControlEventTouchUpInside];
}
}
The PKPaymentRequest
is highly customizable and, therefore, needs to be created by you to keep the same flexibility. Decide what values are needed for your use case.
Swift Example:
private func makeRequest() -> PKPaymentRequest {
let request = PKPaymentRequest()
request.merchantIdentifier = "YOUR_MERCHANT_IDENTIFIER"
request.supportedNetworks = [.visa, .girocard]
request.merchantCapabilities = .threeDSecure
request.countryCode = "DE"
request.currencyCode = "EUR"
request.paymentSummaryItems = [
PKPaymentSummaryItem(label: "Item 1", amount: NSDecimalNumber(decimal: Decimal(33.99))),
PKPaymentSummaryItem(label: "Item 2", amount: NSDecimalNumber(decimal: Decimal(2.99))),
PKPaymentSummaryItem(label: "Total", amount: NSDecimalNumber(decimal: Decimal(36.98)))
]
request.requiredBillingContactFields = [.postalAddress, .emailAddress, .name]
request.requiredShippingContactFields = [.postalAddress, .emailAddress, .name]
let freeShipping = PKShippingMethod(label: "Free Shipping", amount: NSDecimalNumber(decimal: Decimal(0.00)), type: .final)
freeShipping.identifier = "free"
freeShipping.detail = "Arrives in 1-3 business days."
let expressShipping = PKShippingMethod(label: "Express Shipping", amount: NSDecimalNumber(decimal: Decimal(10.00)), type: .final)
expressShipping.identifier = "express"
expressShipping.detail = "Arrives tomorrow"
request.shippingMethods = [freeShipping, expressShipping]
request.applicationData = Data()
return request
}
Objective-C Example:
-(PKPaymentRequest *)makeRequest {
PKPaymentRequest *request = [[PKPaymentRequest alloc] init];
request.merchantIdentifier = @"YOUR_MERCHANT_IDENTIFIER";
request.supportedNetworks = @[PKPaymentNetworkVisa, PKPaymentNetworkGirocard];
request.merchantCapabilities = PKMerchantCapability3DS;
request.countryCode = @"DE";
request.currencyCode = @"EUR";
PKPaymentSummaryItem *item1 = [PKPaymentSummaryItem summaryItemWithLabel:@"Item 1" amount:[NSDecimalNumber decimalNumberWithString:@"33.99"]];
PKPaymentSummaryItem *item2 = [PKPaymentSummaryItem summaryItemWithLabel:@"Item 2" amount:[NSDecimalNumber decimalNumberWithString:@"2.99"]];
PKPaymentSummaryItem *total = [PKPaymentSummaryItem summaryItemWithLabel:@"Total" amount:[NSDecimalNumber decimalNumberWithString:@"36.98"]];
request.paymentSummaryItems = @[item1, item2, total];
request.requiredBillingContactFields = [NSSet setWithArray:@[PKContactFieldPostalAddress, PKContactFieldEmailAddress, PKContactFieldName]];
request.requiredShippingContactFields = [NSSet setWithArray:@[PKContactFieldPostalAddress, PKContactFieldEmailAddress, PKContactFieldName]];
PKShippingMethod *freeShipping = [PKShippingMethod summaryItemWithLabel:@"Free Shipping" amount:[NSDecimalNumber decimalNumberWithString:@"0.00"]];
freeShipping.identifier = @"free";
freeShipping.detail = @"Arrives in 1-3 business days.";
PKShippingMethod *expressShipping = [PKShippingMethod summaryItemWithLabel:@"Express Shipping" amount:[NSDecimalNumber decimalNumberWithString:@"10.00"]];
expressShipping.identifier = @"express";
expressShipping.detail = @"Arrives tomorrow";
request.shippingMethods = @[freeShipping, expressShipping];
request.applicationData = [NSData data];
return request;
}
There are different events that can happen where you will receive callbacks for from the ApplePayHandler
. You have to set a completion on the handlers like this:
Swift
applePayHandler.didAuthorizePayment = { result in
print(result)
}
Objective-C
self.applePayHandler.didAuthorizePayment = ^(PKPaymentAuthorizationResult *result) {
NSLog(@"%@", result);
};
Important
Not all of these events have to be handled. It depends on the request you create and the options you give to the user.
Callback | Note |
---|---|
didAuthorizePayment | Sent after the user has acted on the payment request. |
didSelectShippingContact | Sent when the user has selected a new shipping method. |
onShippingMethodDidChange | Sent when the user has selected a new shipping method. |
onDidSelectPaymentMethod | Sent when the user has selected a new payment card. |
onChangeCouponCode | Sent when the user has selected a new coupon code. |
This will ultimately initiate the payment, you should see Apple Pay open up and the callbacks should be called when a change was made. Lastly when the user concludes the payment, a request will be sent to your provided processPaymentServerUrl
.
Swift
applePayHandler.startPayment(
request: request,
onDidSelectPaymentMethod: { _ in
// Do a proper implementation here like adding the shipping costs if needed.
PKPaymentRequestPaymentMethodUpdate(paymentSummaryItems: request.paymentSummaryItems)
}
) { success in
print("Payment did work \(success)")
}
Objective-C
[self.applePayHandler startPaymentWithRequest:request onDidSelectPaymentMethod:^PKPaymentRequestPaymentMethodUpdate * _Nonnull(PKPaymentMethod *paymentMethod) {
return [[PKPaymentRequestPaymentMethodUpdate alloc] initWithPaymentSummaryItems:request.paymentSummaryItems];
} completion:^(BOOL success) {
NSLog(@"%d", success);
}];
You can find a demonstration project for each language including all features in the corresponding directories:
- Swift: Check out the PCPClientSwiftDemo folder.
- Objective-C: See the PCPClientObjcDemo folder.
Important
Be aware that you will need to provide your own properties, for example AID, MID, PortalKey or Apple Pay server URL at all places which are prefixed with "YOUR_".
See CONTRIBUTING.md
- Checkout develop branch.
- Do the required changes.
- Create a pull-request into main branch.
- After merging the develop branch create a Git tag with the version.
This project is licensed under the MIT License. For more details, see the LICENSE file.