- Get Started
- Guides
- Integrations
- References
- API Reference
- Basic Payment
- Forex
- Authentication
- Card Account
- Apple Pay
- Virtual Account
- Bank Account
- Token Account
- Customer
- Billing Address
- Merchant Billing Address
- Shipping Address
- Merchant Shipping Address
- Merchant
- Corporate
- Recipient
- Marketplace & Cart
- Airline
- Lodging
- Passenger
- Tokenization
- Recurring Migration
- 3D Secure
- Custom Parameters
- Async Payments
- Job
- Risk
- Response Parameters
- Card On File
- Chargeback
- Result Codes
- Payment Methods
- Transaction Flows
- Regression Testing
- Data Retention Policy
- API Reference
- Support
Apple Pay
Apple Pay is easy to set up and gives your customers a simple and secure way to pay using their iPhone or iPad.
This guide explains how to process Apple Pay payments with our SDK.
Configuration
In order to use Apple Pay on a real device, you will need to create keys and a certificate. Here are the steps:
Adding Apple Pay to your app must be done in one of two ways, depending on whether you are using the Ready-to-Use UI or the SDK & Your Own UI. These two ways are covered in the sections below. Please follow the instructions relevant to the approach you have chosen.
Ready-to-Use UI
Request checkout ID
To initiate payment checkout ID should be created. Your app should request a checkout ID from your server. This example uses our sample integration server; please adapt it to use your own backend API.
NSURLRequest *merchantServerRequest = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://YOUR_URL/?amount=100¤cy=EUR&paymentType=DB"]];
[[[NSURLSession sharedSession] dataTaskWithRequest:merchantServerRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
// TODO: Handle errors
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
self.checkoutID = JSON[@"checkoutId"];
}] resume];
let merchantServerRequest = NSURLRequest(url: URL(string: "https://YOUR_URL/?amount=100¤cy=EUR&paymentType=DB")!)
URLSession.shared.dataTask(with: merchantServerRequest as URLRequest) { (data, response, error) in
// TODO: Handle errors
if let json = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any] {
let checkoutID = json?["checkoutId"] as? String
}
}.resume()
Create and configure checkout provider
Create a PKPaymentRequest object
and add it to OPPCheckoutSettings
.
We provide a helper method in OPPPaymentProvider
to construct a PKPaymentRequest
with the given merchantIdentifier,
countryCode,
and the following default values:
- supportedNetworks contain all payment networks
- merchantCapabilities contain threeDSecure
merchantCapabilities
always contain threeDSecure
.
The emv
value is not supported.
OPPPaymentProvider *provider = [OPPPaymentProvider paymentProviderWithMode:OPPProviderModeTest];
OPPCheckoutSettings *checkoutSettings = [[OPPCheckoutSettings alloc] init];
PKPaymentRequest *paymentRequest = [OPPPaymentProvider paymentRequestWithMerchantIdentifier:@"YOUR MERCHANT ID" countryCode:@"YOUR MERCHANT COUNTRY CODE"];
paymentRequest.supportedNetworks = ... // set up supported payment networks
checkoutSettings.applePayPaymentRequest = paymentRequest;
OPPCheckoutProvider *checkoutProvider = [OPPCheckoutProvider checkoutProviderWithPaymentProvider:provider
checkoutID:checkoutID
settings:checkoutSettings];
let provider = OPPPaymentProvider(mode: OPPProviderMode.test)
let checkoutSettings = OPPCheckoutSettings()
let paymentRequest = OPPPaymentProvider.paymentRequest(withMerchantIdentifier: "YOUR MERCHANT ID", countryCode: "YOUR MERCHANT COUNTRY CODE")
paymentRequest.supportedNetworks = ... // set up supported payment networks
checkoutSettings.applePayPaymentRequest = paymentRequest
let checkoutProvider = OPPCheckoutProvider(paymentProvider: provider, checkoutID: checkoutID!, settings: checkoutSettings)
(Optional) Set button type
Choose a button type that best fits with the terminology and flow of your purchase or payment experience. For design guidance, see Apple Pay button guidelines.
// Set button type to Buy
checkoutSettings.applePayType = PKPaymentButtonTypeBuy;
// Set button type to Buy
checkoutSettings.applePayType = PKPaymentButtonType.buy
See PKPaymentButtonType documentation for all available button types.
The default value is plain
.
Present checkout and implement callbacks.
[checkoutProvider presentCheckoutWithPaymentBrand:@"APPLEPAY"
loadingHandler:^(BOOL inProgress) {
// Executed whenever SDK sends request to the server or receives the response.
// You can start or stop loading animation based on inProgress parameter.
} completionHandler:^(OPPTransaction * _Nullable transaction, NSError * _Nullable error) {
if (error) {
// See code attribute (OPPErrorCode) and NSLocalizedDescription to identify the reason of failure.
} else {
if (transaction.redirectURL) {
// Shopper was redirected to the issuer web page.
// Request payment status when shopper returns to the app using transaction.resourcePath or just checkout id.
} else {
// Request payment status for the synchronous transaction from your server using transactionPath.resourcePath or just checkout id.
}
}
} cancelHandler:^{
// Executed if the shopper closes the payment page prematurely.
}];
checkoutProvider?.presentCheckout(withPaymentBrand: "APPLEPAY",
loadingHandler: { (inProgress) in
// Executed whenever SDK sends request to the server or receives the answer.
// You can start or stop loading animation based on inProgress parameter.
}, completionHandler: { (transaction, error) in
if error != nil {
// See code attribute (OPPErrorCode) and NSLocalizedDescription to identify the reason of failure.
} else {
if transaction?.redirectURL != nil {
// Shopper was redirected to the issuer web page.
// Request payment status when shopper returns to the app using transaction.resourcePath or just checkout id.
} else {
// Request payment status for the synchronous transaction from your server using transactionPath.resourcePath or just checkout id.
}
}
}, cancelHandler: {
// Executed if the shopper closes the payment page prematurely.
})
Note: use the brand APPLEPAYTKN when your acquirer should handle the decryption. Please contact the acquirer directly for more information.
Collecting Apple Pay Shipping and Billing Information
Configure the payment request
First of all use the requiredShippingContactFields
and requiredBillingContactFields
properties of the payment request to indicate what billing and shipping information is needed. Then Apple Pay form will prompt shoppers to supply the requested billing and shipping information.
Note that API differs for iOS 9 and 10.
// Enable requesting shipping information
if (@available(iOS 11.0, *)) {
paymentRequest.requiredShippingContactFields = [NSSet setWithObject:PKContactFieldPostalAddress];
} else {
paymentRequest.requiredShippingAddressFields = PKAddressFieldPostalAddress;
}
if #available(iOS 11.0, *) {
paymentRequest.requiredShippingContactFields = Set([PKContactField.postalAddress])
} else {
paymentRequest.requiredShippingAddressFields = .postalAddress
}
// Enable requesting billing information
if (@available(iOS 11.0, *)) {
paymentRequest.requiredBillingContactFields = [NSSet setWithObject:PKContactFieldPostalAddress];
} else {
paymentRequest.requiredBillingAddressFields = PKAddressFieldPostalAddress;
}
if #available(iOS 11.0, *) {
paymentRequest.requiredBillingContactFields = Set([PKContactField.postalAddress])
} else {
paymentRequest.requiredBillingAddressFields = .postalAddress
}
Adopt the OPPCheckoutProviderDelegate protocol
To receive callbacks from the Apple Pay form, make sure your view controller adopts OPPCheckoutProviderDelegate
protocol and you set the checkoutProvider.delegate
property.
// Adopt the OPPCheckoutProviderDelegate protocol
@interface SomeViewController () <OPPCheckoutProviderDelegate>
@end
@implementation SomeViewController
...
- (IBAction)applePayTapped:(id)sender {
// Set a delegate property for the OPPCheckoutProvider instance
self.checkoutProvider.delegate = self;
...
}
@end
// Adopt the OPPCheckoutProviderDelegate protocol
class SomeViewController: UIViewController, OPPCheckoutProviderDelegate {
...
@IBAction func applePayTapped(_ sender: UIButton) {
// Set a delegate property for the OPPCheckoutProvider instance
self.checkoutProvider.delegate = self
...
}
}
Collecting Shipping Information
Apple Pay form calls two delegates when shopper provides shipping information:
- Shipping contact:
checkoutProvider:applePayDidSelectShippingContact:handler:
- Shipping method:
checkoutProvider:applePayDidSelectShippingMethod:handler:
Some shipping methods aren’t available in all areas or have different costs for different addresses. You can update this information by returning new list of shipping methods and summary items in completion block.
Shipping contact
- (void)checkoutProvider:(OPPCheckoutProvider *)checkoutProvider
applePayDidSelectShippingContact:(PKContact *)contact
handler:(void (^)(OPPApplePayRequestShippingContactUpdate * _Nonnull))completion {
// You may want to provide different shipping methods based on shipping information
NSArray *shippingMethods = [self shippingMethodsForContact:contact];
// You may want to change amount of transaction (e.g. by adding tax) based on shipping information
self.contact = contact;
[self updateSummaryItems];
OPPApplePayRequestShippingContactUpdate *update = [[OPPApplePayRequestShippingContactUpdate alloc] initWithErrors:nil paymentSummaryItems:self.summaryItems shippingMethods:shippingMethods];
completion(update);
}
func checkoutProvider(_ checkoutProvider: OPPCheckoutProvider, applePayDidSelectShippingContact contact: PKContact, handler completion: @escaping (OPPApplePayRequestShippingContactUpdate) -> Void) {
// You may want to provide different shipping methods based on shipping information
let shippingMethods = self.shippingMethods(contact: contact)
// You may want to change amount of transaction (e.g. by adding tax) based on shipping information
self.contact = contact
updateSummaryItems()
let update = OPPApplePayRequestShippingContactUpdate.init(errors: nil, paymentSummaryItems: self.summaryItems, shippingMethods: shippingMethods)
completion(update)
}
NOTE: To maintain privacy, the shipping information provided in this delegate is anonymized. The returned contact contains enough information to calculate shipping costs, without revealing sensitive information about the shopper. Full shipping information will be available after shopper authorizes the payment in the checkoutProvider:applePayDidAuthorizePayment:handler
delegate.
Shipping method
- (void)checkoutProvider:(OPPCheckoutProvider *)checkoutProvider
applePayDidSelectShippingMethod:(PKShippingMethod *)shippingMethod
handler:(void (^)(OPPApplePayRequestShippingMethodUpdate * _Nonnull))completion {
// You may want to change amount of transaction based on shipping method cost
self.shippingMethod = shippingMethod;
[self updateSummaryItems];
OPPApplePayRequestShippingMethodUpdate *update = [[OPPApplePayRequestShippingMethodUpdate alloc] initWithPaymentSummaryItems:self.summaryItems];
completion(update);
}
func checkoutProvider(_ checkoutProvider: OPPCheckoutProvider, applePayDidSelect shippingMethod: PKShippingMethod, handler completion: @escaping (OPPApplePayRequestShippingMethodUpdate) -> Void) {
// You may want to change amount of transaction based on shipping method cost
self.shippingMethod = shippingMethod
updateSummaryItems()
let update = OPPApplePayRequestShippingMethodUpdate.init(paymentSummaryItems: self.summaryItems)
completion(update)
}
Collecting billing information
Billing information and full shipping information is available only after shopper authorizes the payment. Implement the checkoutProvider:applePayDidAuthorizePayment:handler
delegate to get this data.
- (void)checkoutProvider:(OPPCheckoutProvider *)checkoutProvider
applePayDidAuthorizePayment:(PKPayment *)payment
handler:(void (^)(OPPApplePayRequestAuthorizationResult * _Nonnull))completion {
OPPApplePayRequestAuthorizationResult *result = nil;
// You may want to validate shipping/billing info
if ([self isValidBillingContact:payment.billingContact]) {
// Return success to continue the payment
result = [[OPPApplePayRequestAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusSuccess
errors:nil];
} else {
NSArray *errors = nil;
if (@available(iOS 11.0, *)) {
// Since iOS 11 you can pass list of errors in billing/shipping info
NSError *error = [PKPaymentRequest paymentBillingAddressInvalidErrorWithKey:CNPostalAddressCountryKey
localizedDescription:@"Some country error message"];
errors = [NSArray arrayWithObject:error];
}
result = [[OPPApplePayRequestAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusFailure
errors:errors];
}
completion(result);
}
func checkoutProvider(_ checkoutProvider: OPPCheckoutProvider, applePayDidAuthorizePayment payment: PKPayment, handler completion: @escaping (OPPApplePayRequestAuthorizationResult) -> Void) {
var result: OPPApplePayRequestAuthorizationResult
// You may want to validate shipping/billing info
if isValidBillingContact(contact: payment.billingContact) {
// Return success to continue the payment
result = OPPApplePayRequestAuthorizationResult.init(status: .success, errors: nil)
} else {
var errors: [Error] = []
if #available(iOS 11.0, *) {
// Since iOS 11 you can pass list of errors in billing/shipping info
let error = PKPaymentRequest.paymentBillingAddressInvalidError(withKey: CNPostalAddressCountryKey, localizedDescription: "Some country error mesage")
errors = [error]
}
result = OPPApplePayRequestAuthorizationResult.init(status: .failure, errors: errors)
}
completion(result)
}
Updating Apple Pay transaction amount
To update Apple Pay transaction amount, you need to
PKPaymentSummaryItem
s in the shipping info delegates,checkoutProvider:continueSubmitting:completion:
delegate. It is the last checkout delegate that is called right before the submitting transaction.- (void)checkoutProvider:(OPPCheckoutProvider *)checkoutProvider
continueSubmitting:(OPPTransaction *)transaction
completion:(void (^)(NSString * _Nullable checkoutID, BOOL abort))completion {
// Update checkout session with the new amount
completion(transaction.paymentParams.checkoutID, NO);
}
func checkoutProvider(_ checkoutProvider: OPPCheckoutProvider, continueSubmitting transaction: OPPTransaction, completion: @escaping (String?, Bool) -> Void) {
// Update checkout session with the new amount
completion(transaction.paymentParams.checkoutID, false)
}
Submitting shopper information
Instead of collecting information by yourself as explained above, you can use the mSDK to collect and submit it. Set in the CheckoutSettings what information should be submitted.
Configure CheckoutSettings
Set applePayContactTypes
property in the CheckoutSettings what information should be submitted.
- OPPCheckoutApplePayContactTypeBillingAddress- The shopper billing address.
- OPPCheckoutApplePayContactTypeCustomer - The shopper name, surname, phone and email.
One or both options can be used.
checkoutSettings.applePayContactTypes = OPPCheckoutApplePayContactTypeBillingAddress | OPPCheckoutApplePayContactTypeCustomer;
checkoutSettings.applePayContactTypes = [.billingAddress, .customer]
SDK & Your Own UI
If you are using our SDK & Your Own UI then there is a little more work to be done, but it is still easy to add. Accepting Apple Pay is quite similar to working with cards. When the shopper approves a payment, your application will receive a PKPayment
object that contains encrypted card details. Create OPPApplePayPaymentParams
with the received payment data and submit a transaction. See below the full Apple Pay flow.
Set up your Apple Pay button
Apple Pay is only available to a subset of iOS users. Before presenting the Apple Pay option to the current user, you should determine whether Apple Pay is available. You can do it using OPPPaymentProvider
helper method.
- (void)viewDidLoad {
[super viewDidLoad];
self.applePayButton.enabled = [OPPPaymentProvider deviceSupportsApplePay];
}
override func viewDidLoad() {
super.viewDidLoad()
applePayButton.isEnabled = OPPPaymentProvider.deviceSupportsApplePay()
}
Create a PKPaymentRequest
Next, when the shopper taps "pay by Apple Pay",
create a PKPaymentRequest object.
We provide a helper method in OPPPaymentProvider
to create one
with the given merchantIdentifier,
countryCode,
and the following default values:
- supportedNetworks contain all payment networks
- merchantCapabilities contain threeDSecure
merchantCapabilities
always contain threeDSecure
.
The emv
value is not supported.
NOTE: See how to register a merchant ID in Apple Pay documentation.
PKPaymentRequest *request = [OPPPaymentProvider paymentRequestWithMerchantIdentifier:@"YOUR MERCHANT ID" countryCode:@"YOUR COUNTRY CODE"];
// Set currency.
request.currencyCode = "USD";
// Create total item. Label should represent your company.
// It will be prepended with the word "Pay" (i.e. "Pay Sportswear $100.00")
NSDecimalNumber *amount = [NSDecimalNumber decimalNumberWithMantissa:10000 exponent:-2 isNegative:NO];
request.paymentSummaryItems = @[[PKPaymentSummaryItem summaryItemWithLabel:@"Sportswear" amount:amount]];
let request = OPPPaymentProvider.paymentRequest(withMerchantIdentifier: "YOUR MERCHANT ID", countryCode: "YOUR COUNTRY CODE")
// Set currency.
request.currencyCode = "USD"
// Create total item. Label should represent your company.
// It will be prepended with the word "Pay" (i.e. "Pay Sportswear $100.00")
let amount = NSDecimalNumber(mantissa: 10000, exponent: -2, isNegative: false)
request.paymentSummaryItems = [PKPaymentSummaryItem(label: "Sportswear", amount: amount)]
Present a PKPaymentAuthorizationViewController
Next, create and present a PKPaymentAuthorizationViewController
with your payment request. Use OPPPaymentProvider
method to validate the final PKPaymentRequest
object.
NOTE: Your view controller should implement
PKPaymentAuthorizationViewControllerDelegate
protocol to respond to user interaction with that view controller.- (void)applePayTapped {
PKPaymentRequest *request = ...; // See above
if ([OPPPaymentProvider canSubmitPaymentRequest:request]) {
PKPaymentAuthorizationViewController *vc = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:request];
vc.delegate = self;
[self presentViewController:vc animated:YES completion:nil];
} else {
NSLog(@"Apple Pay not supported.");
}
}
func applePayTapped() {
let request = PKPaymentRequest() // See above
if OPPPaymentProvider.canSubmitPaymentRequest(request) {
if let vc = PKPaymentAuthorizationViewController(paymentRequest: request) as PKPaymentAuthorizationViewController? {
vc.delegate = self
present(vc, animated: true, completion: nil)
} else {
NSLog(@"Apple Pay not supported.");
}
}
}
Finally, implement the necessary PKPaymentAuthorizationViewControllerDelegate
methods. In your implementation of paymentAuthorizationViewController:didAuthorizePayment:completion:
, create OPPApplePayPaymentParams
and submit a debit transaction.
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
didAuthorizePayment:(PKPayment *)payment
completion:(void (^)(PKPaymentAuthorizationStatus))completion {
OPPApplePayPaymentParams *params = [OPPApplePayPaymentParams applePayPaymentParamsWithCheckoutID:checkoutID
tokenData:payment.token.paymentData];
// Check if parameters are valid and submit transaction.
[self.provider submitTransaction:[OPPTransaction transactionWithPaymentParams:params] completionHandler:^(OPPTransaction *transaction, NSError *error) {
if (error) {
// See code attribute (OPPErrorCode) and NSLocalizedDescription to identify the reason of failure.
} else {
// Send request to your server to obtain transaction status.
}];
}
- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller {
[controller dismissViewControllerAnimated:YES completion:nil];
}
func paymentAuthorizationViewController(_ controller: PKPaymentAuthorizationViewController, didAuthorizePayment payment: PKPayment, completion: @escaping (PKPaymentAuthorizationStatus) -> Void) {
if let params = try? OPPApplePayPaymentParams(checkoutID: checkoutID, tokenData: payment.token.paymentData) as OPPApplePayPaymentParams? {
provider.submitTransaction(OPPTransaction(paymentParams: params!), completionHandler: { (transaction, error) in
if (error != nil) {
// See code attribute (OPPErrorCode) and NSLocalizedDescription to identify the reason of failure.
} else {
// Send request to your server to obtain transaction status.
}
})
}
}
func paymentAuthorizationViewControllerDidFinish(_ controller: PKPaymentAuthorizationViewController) {
controller.dismiss(animated: true, completion: nil)
}