Judopay Documentation

Alternative Payment Methods

Apple Pay™

Note

Apple Pay™ for Mobile only.

Apple Pay™ provides an easy and secure way to pay for physical goods and services such as groceries, clothing, tickets, and reservations in your iOS apps or on your website.

Using Touch ID, users can quickly and securely provide all their payment and shipping information to check out with a single touch.

Judopay’s iOS Objective-C SDK lets your app process Apple Pay™ payments.

 

Note

It is important to understand the difference between Apple Pay™ and an In-App Purchase.

Use Apple Pay™ to sell physical goods and services.

Use an In-App Purchase to sell virtual goods such as premium content for your app, and subscriptions for digital content.

For consumers, the Apple Pay™ experience starts with:

  1. Registering their payment and shipping information into the Wallet app on their Apple devices.

  2. Once registered, consumers can pay simply and securely using Touch ID to authenticate a transaction.

  3. Each transaction processed through Apple Pay™ is assigned a one-time payment number and a dynamic security code.

    1. This information is encrypted and used in place of credit or debit card details.

Effective implementations of Apple Pay™ can radically improve your payment process by allowing for a smoother ‘guest checkout’, while still capturing all the relevant information needed to fulfil a purchase, for example shipping information.

Apple Pay™

System Requirements:

  • A compatible Apple device: iPhone 6 & 6 Plus | iPad Air 2 | iPad mini 3 | or newer

  • OS 8.1 or newer

  • Xcode 6.1 or newer

Getting Started with Apple Pay™

Tip

We recommend creating a Merchant ID for each Merchant (i.e. business) accepting payments within your app.

Create a Merchant ID

Apple Certificate

Step

Description

One.png

Access your Apple Developer Account.

Navigate to Certificates, Identifiers & Profiles.

Two.png

From the side menu, click Merchant IDs.

Three.png

In the iOS Merchant ID Settings screen, click the add button.

Four.png

Set your Merchant ID.

The identifier you enter should be a reverse DNS style identifier prefixed with the word.

Five.png

Click Done.

Apple Pay™ Support

Caution

Apple Pay™ is not supported on all Apple devices.

Before invoking any Apple Pay™ functionality within your app, test if it is supported on the device by performing these checks:

  • Use [PKPaymentAuthorizationViewController canMakePayments]

    Checks if the device supports Apple Pay™ and has it enabled.

    Queries both the device hardware and whether Apple Pay™ is enabled in the user’s region.

  • Use [PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks]

    A more detailed check to query whether a user has a registered card with particular card schemes.

    Useful if you do not accept all card types.

Both methods are explained in the Apple developer documentation here.

Create an Apple Pay™ Certificate

Pre-Requisite:

Request a Certificate Signing Request (CSR) file from Judopay.

When you’ve received your CSR, you can create your Apple Pay™ certificate.

To create your Apple Pay™ certificate:

Apple Pay Certificate

Step

Description

One.png

From the side menu, select either:

  • Certificates > All

  • Merchant ID

Two.png

The screen appears describing how to manually create your Certificate Signing Request (CSR).

As you’ve already obtained your CSR from Judopay, click Continue.

Three.png

You will be prompted to state if you are processing transactions outside the United States.

Select No.

Four.png

Click Continue.

Five.png

Click Choose File to upload the CSR file provided by Judopay.

Six.png

Click Generate.

Seven.png

The confirmation screen appears.

Your certificate is ready to download.

Click Download.

Eight.png

Click Done.

To complete your Apple Pay™ set-up send the certificate to Judopay.

Once received, we will add the certificate to your account and confirm it has been added.

Note

Apple Certificates expire just over two years after generation. For example a certificate generated on 13th May 2020 will expire on the 11th June 2021.

To generate a new certificate follow the steps above.

Set Up Apple Pay™ Entitlement

Apple Pay™ is built into the PassKit framework, which means you will need to configure the entitlement.

To set up the entitlement:

Apple Pay Entitlement

Step

Description

One.png

Select your build Target.

Two.png

Select Capabilities.

Three.png

Set the entitlement to Enabled.

Four.png

Add the Merchant ID created earlier to the app.

You may need to refresh the list.

Five.png

Open the entitlements file to confirm the Merchant ID has been added to your app.

 

Your account is now ready to process Apple Pay™ payments with Judopay.

Configure the Judopay SDK to start making payments.

Apple Pay™ Button

Apple Pay™ allows the consumer to:

  • Bypass the standard checkout flow

  • Complete their payment with speed

Apple Pay Button

When integrating with Apple Pay™, it is recommended to consider when to introduce the Apple Pay™ button.

This can be:

  • On a single item product listing page

  • Within a basket page with multiple items

  • Both of the above scenarios

The Apple Pay™ button enables consumers to make a purchase from the specific page they are browsing. By tapping the Apple Pay™ button, the payment sheet is invoked to begin the checkout process.

For more information on the Apple Pay™ button, see Apple’s guidance of the PKPaymentButton Class Reference.

Best Practice Testing

Caution

You can test Apple Pay™ in the sandbox environment with the sandbox cards, however please note these test transactions will not work going upstream.

To test Apple Pay™ transactions, point to the live environment and use live cards.

We recommend performing | Pre-Authorizations | Card Payments | Full Refunds: via the Judopay Dashboard > History, or via an API call.

We strongly recommend testing Apple Pay™ through each of these scenarios before you release the app:

  • Unsupported Device

    Use a non-supported device in order to verify the whole recognition workflow works as expected.

  • Card not Supported

    Use a card issued by a bank that does not support Apple Pay™. You can also use the test cards provided on the Judopay Dashboard to validate the error returned and expected behaviour.

  • Payment Cancelled

    Cancel a transaction in process and see the results in the app and in your Judopay Dashboard history.

  • Poor / Loss of Connection

    While a transaction is being processed, disconnect the internet connection to see if the app responds as expected.

Google Pay™

Note

Google Pay™ for Mobile only.

Integrating Google Pay™ in your app, allows for your customers on Android devices to check out using payment cards they have saved to their Google Wallet.

User Requirements

  • Google Pay™ works with credit or debit cards from participating card issuing banks

  • Android devices running versions 5.0+ (Lollipop)

Consumers can use devices that are not NFC-enabled, to make Google Pay™ purchases in merchant’s mobile apps.

Judo Android SDK

This section assumes you have Judopay’s Android SDK as a dependency in your Android application.

If you do not, to add the Android SDK into your app's dependencies using gradle, see Android SDK.

Configuring the Wallet

There are two environments for Google Pay™:

  • Sandbox

  • Production 

Ensure you configure the Wallet to specify your payment environment.

This is reflected by the WalletConstants enum in the android wallet package:

public static final int PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_PRODUCTION;

public static final int PAYMENTS_ENVIRONMENT = WalletConstants.ENVIRONMENT_SANDBOX;

Google Pay™ supports both tokenized and non-tokenized cards. 

Tokenised:  Google Pay™ generates a token which represents the card. Only this token is sent when making a payment. Your customer's card number does not leave Google Pay™.

For security reasons, Judopay only currently supports tokenized cards. Therefore you must configure your application to only support the tokenized card method. 

Note

This means any invalid cards will not appear as a payment option when your consumer tries to pay with your application.

public static final List<Integer> SUPPORTED_METHODS = Arrays.asList(
        // PAYMENT_METHOD_TOKENIZED_CARD refers to EMV tokenized credentials stored in the
        // Google Pay app, assuming it's installed.
        WalletConstants.PAYMENT_METHOD_TOKENIZED_CARD
);

1. Set the Gateway name to judopay:

public static final String GATEWAY_TOKENIZATION_NAME = "judopay";

2. When creating a new PaymentsClient (another Android class), initialise it with the PAYMENTS_ENVIRONMENT, and the activity launching your payment:

public static PaymentsClient createPaymentsClient(Activity activity) {
    Wallet.WalletOptions walletOptions = new Wallet.WalletOptions.Builder()
            .setEnvironment(Constants.PAYMENTS_ENVIRONMENT)
            .build();
    return Wallet.getPaymentsClient(activity, walletOptions);
}

3. Set the tokenization parameters with your merchant ID (Judo ID):

public static final List<Pair<String, String>> GATEWAY_TOKENIZATION_PARAMETERS = Arrays.asList(
    Pair.create("gatewayMerchantId", "{YOUR_JUDO_ID}")
);

4. Specify the card networks to support, and the allowed shipping countries. This might vary depending on your application and product.

// The allowed networks to be requested from the API. If the user has cards from networks not
// specified here in their account, these will not be offered for them to choose in the popup.
public static final List<Integer> SUPPORTED_NETWORKS = Arrays.asList(
        WalletConstants.CARD_NETWORK_AMEX,
        WalletConstants.CARD_NETWORK_DISCOVER,
        WalletConstants.CARD_NETWORK_VISA,
        WalletConstants.CARD_NETWORK_MASTERCARD
);

// Supported countries for shipping (use ISO 3166-1 alpha-2 country codes).
// Relevant only when requesting a shipping address.
public static final List<String> SHIPPING_SUPPORTED_COUNTRIES = Arrays.asList(
        "US",
        "GB"
);

Generating a Google Pay™ Payment

In your checkout activity:

  • Find the view/button to trigger the payment

  • Add the request payment listener

The Google Pay sample application project has a sample view layout for a Google Pay button you can use (googlepay_button.xml) which follows the Google Pay style conventions.

// Arbitrarily-picked result code.
private static final int LOAD_PAYMENT_DATA_REQUEST_CODE = 991;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_checkout);


    mGooglePayButton = findViewById(R.id.googlepay_button);
    mGooglePayStatusText = findViewById(R.id.googlepay_status);

    mGooglePayButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            requestPayment(view);
        }
    });

    // It's recommended to create the PaymentsClient object inside the onCreate method.
    mPaymentsClient = PaymentsUtil.createPaymentsClient(this);
    checkIsReadyToPay();
}

// This method is called when the Pay with Google button is clicked.
public void requestPayment(View view) {
    // Disables the button to prevent multiple clicks.
    mGooglePayButton.setClickable(false);

    // The price provided to the API should include taxes and shipping.
    // This price is not displayed to the user.
    String price = PaymentsUtil.microsToString(YOUR_ITEM_PRICE);

    TransactionInfo transaction = PaymentsUtil.createTransaction(price);
    PaymentDataRequest request = PaymentsUtil.createPaymentDataRequest(transaction);
    Task<PaymentData> futurePaymentData = mPaymentsClient.loadPaymentData(request);

    // Since loadPaymentData may show in the UI asking the user to select a payment method, we use
    // AutoResolveHelper to wait for the user interacting with it. Once completed,
    // onActivityResult will be called with the result.
    AutoResolveHelper.resolveTask(futurePaymentData, this, LOAD_PAYMENT_DATA_REQUEST_CODE);
}

private void checkIsReadyToPay() {
    // The call to isReadyToPay is asynchronous and returns a Task. We need to provide an
    // OnCompleteListener to be triggered when the result of the call is known.
    PaymentsUtil.isReadyToPay(mPaymentsClient).addOnCompleteListener(
            new OnCompleteListener<Boolean>() {
                public void onComplete(Task<Boolean> task) {
                    try {
                        boolean result = task.getResult(ApiException.class);
                        setGooglePayAvailable(result);
                    } catch (ApiException exception) {
                        // Process error
                        Log.w("isReadyToPay failed", exception);
                    }
                }
            });
}

private void setGooglePayAvailable(boolean available) {
    // If isReadyToPay returns true, show the button and hide the "checking" text. Otherwise,
    // notify the user that Pay with Google is not available.
    // Please adjust to fit in with your current user flow. You are not required to explicitly
    // let the user know if isReadyToPay returns false.
    if (available) {
        mGooglePayStatusText.setVisibility(View.GONE);
        mGooglePayButton.setVisibility(View.VISIBLE);
    } else {
        mGooglePayStatusText.setText(R.string.googlepay_status_unavailable);
    }
}

Create the PaymentDataRequest, passing in the gateway name and parameters set earlier.

Ensure to set the tokenization type as: WalletConstants.PAYMENT_METHOD_TOKENIZATION_TYPE_PAYMENT_GATEWAY:

public static PaymentDataRequest createPaymentDataRequest(TransactionInfo transactionInfo) {
    PaymentMethodTokenizationParameters.Builder paramsBuilder =
            PaymentMethodTokenizationParameters.newBuilder()
                    .setPaymentMethodTokenizationType(
                            WalletConstants.PAYMENT_METHOD_TOKENIZATION_TYPE_PAYMENT_GATEWAY)
                    .addParameter("gateway", Constants.GATEWAY_TOKENIZATION_NAME);
    for (Pair<String, String> param : Constants.GATEWAY_TOKENIZATION_PARAMETERS) {
        paramsBuilder.addParameter(param.first, param.second);
    }

    return createPaymentDataRequest(transactionInfo, paramsBuilder.build());
}

private static PaymentDataRequest createPaymentDataRequest(TransactionInfo transactionInfo, PaymentMethodTokenizationParameters params) {
    PaymentDataRequest request =
            PaymentDataRequest.newBuilder()
                    .setPhoneNumberRequired(false)
                    .setEmailRequired(true)
                    .setShippingAddressRequired(true)

                    // Omitting ShippingAddressRequirements altogether means all countries are
                    // supported.
                    .setShippingAddressRequirements(
                            ShippingAddressRequirements.newBuilder()
                                    .addAllowedCountryCodes(Constants.SHIPPING_SUPPORTED_COUNTRIES)
                                    .build())

                    .setTransactionInfo(transactionInfo)
                    .addAllowedPaymentMethods(Constants.SUPPORTED_METHODS)
                    .setCardRequirements(
                            CardRequirements.newBuilder()
                                    .addAllowedCardNetworks(Constants.SUPPORTED_NETWORKS)
                                    .setAllowPrepaidCards(true)
                                    .setBillingAddressRequired(true)

                                    // Omitting this parameter will result in the API returning
                                    // only a "minimal" billing address (post code only).
                                    .setBillingAddressFormat(WalletConstants.BILLING_ADDRESS_FORMAT_FULL)
                                    .build())
                    .setPaymentMethodTokenizationParameters(params)

                    // If the UI is not required, a returning user will not be asked to select
                    // a card. Instead, the card they previously used will be returned
                    // automatically (if still available).
                    // Prior whitelisting is required to use this feature.
                    .setUiRequired(true)
                    .build();

    return request;
}

Handle a Successful Payment

Catch the payment result in your checkout activity:

public void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
        case LOAD_PAYMENT_DATA_REQUEST_CODE:
            switch (resultCode) {
                case Activity.RESULT_OK:
                    PaymentData paymentData = PaymentData.getFromIntent(data);
                    handlePaymentSuccess(paymentData);
                    break;
                case Activity.RESULT_CANCELED:
                    // Nothing to here normally - the user simply cancelled without selecting a
                    // payment method.
                    break;
                case AutoResolveHelper.RESULT_ERROR:
                    Status status = AutoResolveHelper.getStatusFromIntent(data);
                    handleError(status.getStatusCode());
                    break;
            }

            // Re-enables the Pay with Google button.
            mGooglePayButton.setClickable(true);
            break;
    }
}

 

The function below demonstrates how to handle the payment request returned from the intent, and send on the necessary tokenized card details to the Judopay API to be processed:

private void handlePaymentSuccess(PaymentData paymentData) {
    // PaymentMethodToken contains the payment information, as well as any additional
    // requested information, such as billing and shipping address.
    PaymentMethodToken token = paymentData.getPaymentMethodToken();

    // getPaymentMethodToken will only return null if PaymentMethodTokenizationParameters was
    // not set in the PaymentRequest.
    if (token != null) {
        String encryptedToken = token.getToken();
        String cardNetwork = paymentData.getCardInfo().getCardNetwork();
        String cardDetails = paymentData.getCardInfo().getCardDetails();

        JudoApiService apiService = getJudo().getApiService(getApplicationContext());
        GooglePayRequest request = getGooglePayRequest(encryptedToken, cardNetwork, cardDetails);
        apiService.googlePayPreAuth(request);
    }
}

private GooglePayRequest getGooglePayRequest(String encryptedToken, String cardNetwork, string cardDetails) {
    return new GooglePayRequest.Builder()
            .setJudoId("YOUR_JUDO_ID")
            .setGooglePayWallet(new GooglePayWallet.Builder()
                    .setCardNetwork(cardNetwork)
                    .setCardDetails(cardDetails)
                    .setToken(encryptedToken)
                    .build())
            .setAmount(YOUR_PRICE)
            .setCurrency(Currency.GBP)
            .setConsumerReference(UNIQUE_GUID)
            .build();
}