Generate a client token
Before you can initialize BTPaymentFlowDriver
, you will need to set up the SDK and initialize it with a client token generated on your server.
Specify a merchant account
If you would like to use a merchant account ID other than your default, specify the merchant_account_id when generating the client token.
Using 3DS
To enable 3DS, set up a URL Scheme in your project. This allows your app to switch to a browser or SFSafariViewController
to complete the 3D Secure verification workflow and return.
Drop-in UI
If you haven't already, include the Drop-in in your project.
To use 3DS 2 with our Drop-in UI, set threeDSecureVerification
on your BTDropInRequest
to true.
You will also need to create a BTThreeDSecureRequest
object with relevant customer and transaction data in order to minimize the need for issuing banks to present authentication challenges to customers. This object must contain the following fields:
amount
versionRequested
(You should passBTThreeDSecureVersion2
here)
And should contain as many of the following fields as possible:
email
billingAddress
additionalInformation
BTDropInRequest *request = [[BTDropInRequest alloc] init];
request.threeDSecureVerification = YES;
BTThreeDSecureRequest *threeDSecureRequest = [[BTThreeDSecureRequest alloc] init];
threeDSecureRequest.amount = [NSDecimalNumber decimalNumberWithString:@"10"];
threeDSecureRequest.email = @"test@email.com";
threeDSecureRequest.versionRequested = BTThreeDSecureVersion2;
BTThreeDSecurePostalAddress *address = [BTThreeDSecurePostalAddress new];
address.givenName = @"Jill"; // ASCII-printable characters required, else will throw a validation error
address.surname = @"Doe"; // ASCII-printable characters required, else will throw a validation error
address.phoneNumber = @"5551234567";
address.streetAddress = @"555 Smith St";
address.extendedAddress = @"#2";
address.locality = @"Chicago";
address.region = @"IL";
address.postalCode = @"12345";
address.countryCodeAlpha2 = @"US";
threeDSecureRequest.billingAddress = address;
// Optional additional information.
// For best results, provide as many of these elements as possible.
BTThreeDSecureAdditionalInformation *additionalInformation = [BTThreeDSecureAdditionalInformation new];
additionalInformation.shippingAddress = address;
threeDSecureRequest.additionalInformation = additionalInformation;
BTDropInRequest *dropinRequest = [[BTDropInRequest alloc] init];
dropInRequest.threeDSecureVerification = YES;
dropInRequest.threeDSecureRequest = threeDSecureRequest;
BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:self.authorizationString request:dropInRequest handler:^(BTDropInController *dropInController, BTDropInResult *result, NSError *error) {
if (error) {
// Handle error
} else if (result.isCancelled) {
// Handle user cancelled flow
} else {
// Use the nonce returned in `result.paymentMethod`
}
[dropInController dismissViewControllerAnimated:YES completion:nil];
}];
Custom UI
3DS support with Custom UI can be implemented via CocoaPods or Carthage.
CocoaPods
3DS 2 support requires Braintree version 4.26.3 or higher, as well as the Payment Flow subspec. Update your Podfile to require at least the minimum version and include the Payment Flow subspec:
pod 'Braintree'
pod 'Braintree/PaymentFlow'
Carthage
Add github "braintree/braintree_ios"
to your Cartfile
, and add the frameworks to your project.
For 3DS 2, you must add the following framework:
CardinalMobile.framework
To use 3DS, start by adding an import statement:
#import "BraintreePaymentFlow.h"
@interface YourCheckoutViewController () <BTViewControllerPresentingDelegate>
@property (nonatomic, strong, readwrite) BTPaymentFlowDriver *paymentFlowDriver;
@end
Then initialize the BTPaymentFlowDriver
and set the viewControllerPresentingDelegate
:
- (void)setupPaymentFlowDriver {
self.paymentFlowDriver = [[BTPaymentFlowDriver alloc] initWithAPIClient:self.apiClient];
self.paymentFlowDriver.viewControllerPresentingDelegate = self;
}
Your view controller should conform to BTViewControllerPresentingDelegate
in order to handle view controller presentation.
- (void)paymentDriver:(id)driver requestsPresentationOfViewController:(UIViewController *)viewController {
[self presentViewController:viewController animated:YES completion:nil];
}
- (void)paymentDriver:(id)driver requestsDismissalOfViewController:(UIViewController *)viewController {
[self dismissViewControllerAnimated:YES completion:nil];
}
Once configuration is complete, you will need to create a BTThreeDSecureRequest
with relevant customer and transaction data in order to minimize the need for issuing banks to present authentication challenges to customers. This object must contain the following fields:
amount
nonce
versionRequested
(You should passBTThreeDSecureVersion2
here)
And should contain as many of the following fields as possible:
email
billingAddress
additionalInformation
BTThreeDSecureRequest *threeDSecureRequest = [[BTThreeDSecureRequest alloc] init];
threeDSecureRequest.amount = [NSDecimalNumber decimalNumberWithString:@"10"];
threeDSecureRequest.nonce = tokenizedCard.nonce;
threeDSecureRequest.email = @"test@email.com";
threeDSecureRequest.versionRequested = BTThreeDSecureVersion2;
BTThreeDSecurePostalAddress *address = [BTThreeDSecurePostalAddress new];
address.givenName = @"Jill"; // ASCII-printable characters required, else will throw a validation error
address.surname = @"Doe"; // ASCII-printable characters required, else will throw a validation error
address.phoneNumber = @"5551234567";
address.streetAddress = @"555 Smith St";
address.extendedAddress = @"#2";
address.locality = @"Chicago";
address.region = @"IL";
address.postalCode = @"12345";
address.countryCodeAlpha2 = @"US";
threeDSecureRequest.billingAddress = address;
// Optional additional information.
// For best results, provide as many of these elements as possible.
BTThreeDSecureAdditionalInformation *additionalInformation = [BTThreeDSecureAdditionalInformation new];
additionalInformation.shippingAddress = address;
threeDSecureRequest.additionalInformation = additionalInformation;
Then, call startPaymentFlow
, passing in the ThreeDSecureRequest
.
- (IBAction)tappedCheckout {
// Create a BTCard based on the UI state
BTCard *details = [[BTCard alloc] init];
details.number = self.cardNumberField.text;
details.expirationMonth = self.expirationMonthField.text;
details.expirationYear = self.expirationYearField.text;
// Tokenize the card
[self.cardClient tokenizeCard:details completion:^(BTCardNonce *tokenizedCard, NSError *error) {
if (error) {
// Handle errors
return;
}
// Make sure that self conforms to the BTThreeDSecureRequestDelegate protocol
threeDSecureRequest.threeDSecureRequestDelegate = self;
[self.paymentFlowDriver startPaymentFlow:request completion:^(BTPaymentFlowResult *result, NSError *error) {
if (error) {
// Handle error
} else if (result) {
BTThreeDSecureResult *threeDSecureResult = (BTThreeDSecureResult *)result;
if (threeDSecureResult.tokenizedCard.threeDSecureInfo.liabilityShiftPossible) {
if (threeDSecureResult.tokenizedCard.threeDSecureInfo.liabilityShifted) {
// 3D Secure authentication success
} else {
// 3D Secure authentication failed
}
} else {
// 3D Secure authentication was not possible
}
// Use the `threeDSecureResult.tokenizedCard.nonce`
}
}];
}];
}
- (void)onLookupComplete:(__unused BTThreeDSecureRequest *)request result:(__unused BTThreeDSecureLookup *)lookup next:(void (^)(void))next {
// Optionally inspect the lookup result and prepare UI if a challenge is required
next();
}
If the user successfully completes the 3D Secure process, the
startPaymentFlow
callback block will receive aBTThreeDSecureResult
with atokenizedCard
property. You should transmit thetokenizedCard.nonce
to your server and create a transaction.If the user cancels the 3D Secure authentication, the completion block will be called with an
error
wherecode
isBTPaymentFlowDriverErrorTypeCanceled
.If the 3D Secure process fails, the completion block will be called with an
error
.
In order to perform 3D Secure authentication again, a new nonce needs to be supplied.
For each request to verify a card, the completion block will be called exactly once.
Verify a vaulted credit card
First, on the server, generate and return a payment method nonce for the vaulted credit card.
Then on the client, you can use the startPaymentFlow:completion:
method just as before and pass it the newly-generated nonce.
Validation errors
Braintree will evaluate any fields passed against Cardinal's documentation. You will receive a validation error from Braintree if a field is incorrect.
Advanced client-side options
We expose additional information about the authentication request that you can use for more advanced UI flows or risk assessment. You should be aware that making such assessments may result in accepting the liability for fraudulent transactions.
These parameters pass through the client-side first and should not be trusted for your server-side risk assessment. They should be used for UI flow only.
// In this example, `card` is a `BTCardNonce`.
if (card.threeDSecureInfo.liabilityShiftPossible) {
if (card.threeDSecureInfo.liabilityShifted) {
// 3D Secure authentication success
} else {
// 3D Secure authentication failed
}
} else {
// 3D Secure authentication was not possible
}
liabilityShifted
indicates that 3D Secure worked and authentication succeeded. This will also be true if the issuing bank does not support 3D Secure, but the payment method does. In both cases, the liability for fraud has been shifted to the bank. You should go on creating a transaction using the new nonce.liabilityShiftPossible
indicates that the payment method was eligible for 3D Secure. IfliabilityShifted
isfalse
, then the user failed 3D Secure authentication. In this situation, the card brands recommend asking the user for another form of payment. However, if you have server-side risk assessment processes that allow for it, you can still use the new nonce to create a transaction. If you want to use a nonce that did not pass 3D Secure authentication, you need to set therequired
option tofalse
in your server integration.- If both of the above values are
false
then this card was ineligible for 3D Secure. You can continue to create the transaction with the new nonce. However, liability shift will not apply to this transaction. This case may be useful if you would like to ask the user for additional verification (AVS, etc).
Using 3D Secure with a CVV-only nonce
If you want to use a CVV-only nonce when creating a transaction with 3D Secure, you will need to pass a 3D Secure Authentication ID together with a CVV-only nonce when creating a transaction.