Payment flow

Generate a client token

important

You must generate a client token if you want to use 3D Secure. Tokenization keys can't be used when processing 3D Secure transactions.

Before you can initialize BTPaymentFlowDriver, you will need to set up the SDK and initialize with a client token generated on your server.

Update your Podfile to include the Payment Flow subspec, like this:

availability

To use 3D Secure, integrate with iOS SDK v4.11.0+.

Ruby
Copy
Copied
pod 'Braintree'
pod 'Braintree/PaymentFlow'

Setup for app switch

To handle payments that involve switching to another app or SFSafariViewController for authentication, you must register a URL type and configure your app to return from app switches.

Register a URL type

  1. In Xcode, click on your project in the Project Navigator and navigate to App Target > Info > URL Types
  2. Click [+] to add a new URL type
  3. Under URL Schemes, enter your app switch return URL scheme. This scheme must start with your app's Bundle ID and be dedicated to Braintree app switch returns. For example, if the app bundle ID is com.your-company.Your-App, then your URL scheme could be com.your-company.Your-App.payments.
important

If you have multiple app targets, be sure to add the return URL type for all of the targets.

Testing the URL type

You can test out your new URL scheme by opening up a URL that starts with it (e.g. com.your-company.Your-App.payments://test) in Mobile Safari on your iOS Device or Simulator.

In addition, always test your app switching on a real device.

Update your application delegate

In your AppDelegate's application:didFinishLaunchingWithOptions: implementation, use setReturnURLScheme: with the value you set above.

For example:

Objective-C Swift
Copy
Copied
#import "AppDelegate.h"
#import "BraintreeCore.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [BTAppSwitch setReturnURLScheme:@"com.your-company.Your-App.payments"];
    return YES;
}

Then in your application delegate, pass the payment authorization URL to Braintree for finalization:

Objective-C Swift
Copy
Copied
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
    if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.payments"] == NSOrderedSame) {
        return [BTAppSwitch handleOpenURL:url options:options];
    }
    return NO;
}

// If you support iOS 7 or 8, add the following method.
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    if ([url.scheme localizedCaseInsensitiveCompare:@"com.your-company.Your-App.payments"] == NSOrderedSame) {
        return [BTAppSwitch handleOpenURL:url sourceApplication:sourceApplication];
    }
    return NO;
}

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.

note

This merchant account ID must match the merchant account ID used to create the transaction.

Render a checkout page

You can structure your native checkout flow however you'd like. If you don't already have a credit card form, consider our Drop-in UI.

Start by adding an import statement:

Objective-C Swift
Copy
Copied
#import "BraintreePaymentFlow.h"

@interface YourCheckoutViewController () <BTViewControllerPresentingDelegate>

@property (nonatomic, strong, readwrite) BTPaymentFlowDriver *paymentFlowDriver;

@end

Then initialize the BTPaymentFlowDriver and set the viewControllerPresentingDelegate:

Objective-C Swift
Copy
Copied
- (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.

Objective-C Swift
Copy
Copied
- (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];
}

Verify a credit card

You can verify transactions with startPaymentFlow:completion:. This call will refer to the card data based on the payment method nonce and may challenge the cardholder with a 3D Secure authentication, if the card is enrolled in a 3D Secure program and the card-issuing bank requires this verification.

The transaction amount is required at verification for two reasons. First of all, it's an additional check to make sure the transaction being verified is the same as the one that is eventually authorized and settled. For this reason, the amount submitted for verification must match the amount sent to the Braintree server for authorization. Additionally, some issuers use the amount to help determine whether they should challenge the user to authenticate.

Objective-C Swift
Copy
Copied
- (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;
        }

        BTThreeDSecureRequest *request = [[BTThreeDSecureRequest alloc] init];
        request.amount = [NSDecimalNumber decimalNumberWithString:@"10"];
        request.nonce = tokenizedCard.nonce;
        [self.paymentFlowDriver startPaymentFlow:request completion:^(BTPaymentFlowResult * _Nonnull result, NSError * _Nonnull 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`
            }
        }];
    }];
}
  • If the user successfully completes the 3D Secure process, the callback block will receive a BTThreeDSecureResult with a tokenizedCard property. You should transmit the tokenizedCard.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 where code is BTPaymentFlowDriverErrorTypeCanceled.

  • 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 Cardinals' documentation. You will receive a validation error from Braintree if a field is incorrect.

American Express SafeKey

If you're a US-based merchant configured for Amex SafeKey, you need to pass additional parameters for the transaction to be evaluated for fraud.

We recommend passing most, if not all, of the parameters to qualify for Amex SafeKey. The more parameters you send, the more likely you are to successfully contest a chargeback.

Objective-C Swift
Copy
Copied
BTThreeDSecureRequest *request = [[BTThreeDSecureRequest alloc] init];
request.amount = [NSDecimalNumber decimalNumberWithString:@"10.32"];
request.nonce = tokenizedCard.nonce;

request.mobilePhoneNumber = @"5151234321";
request.email = @"tester@example.com";
request.shippingMethod = @"03";

BTThreeDSecurePostalAddress *address = [BTThreeDSecurePostalAddress new];
address.firstName = @"Joe";
address.lastName = @"Guy";
address.phoneNumber = @"12345678";
address.streetAddress = @"555 Smith St.";
address.extendedAddress = @"#5";
address.locality = @"Oakland";
address.region = @"CA";
address.countryCodeAlpha2 = @"US";
address.postalCode = @"54321";
request.billingAddress = address;

Although these additional parameters are only necessary when using Amex SafeKey, you can safely pass them for other card brands as well.

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.

Objective-C Swift
Copy
Copied
// 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
}
  1. 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.
  2. liabilityShiftPossible indicates that the payment method was eligible for 3D Secure. If liabilityShifted is false, 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 the required option to false in your server integration.
  3. 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).
important

For American Express SafeKey, liabilityShifted may be returned as true but Amex may later revoke the liability shift for the transaction based on your merchant behavior and fraud rate. For more details, see American Express's documentation.

Next Page: Server-side →

Still have questions?

If you can’t find an answer, contact our Support team