Skip to main content

React Native SDK Payment Sheet UI

React Native SDK > Payment Sheet UI

Use the pre-built Payment Sheet UI and implement custom theming and payment methods.

Step 1: Install the SDK

To install the React Native SDK package, run one of the following commands in your project's directory:

npm install @westpac-developer/react-native-sdk
yarn add @westpac-developer/react-native-sdk

If you require additional type support (e.g. for QuickStreamGateway, ApiConfig, or payment request types when building a Custom UI features), also install the React Native Core package:

npm install @westpac-developer/react-native-core
yarn add @westpac-developer/react-native-core

Install dependencies

Install the required peer dependencies:

npm install @gorhom/bottom-sheet @react-native-clipboard/clipboard \
        @react-navigation/native @react-navigation/stack \
        expo-checkbox lucide-react-native \
        react-native-gesture-handler react-native-payment-icons \
        react-native-reanimated react-native-safe-area-context \
        react-native-screens react-native-svg
yarn add @gorhom/bottom-sheet @react-native-clipboard/clipboard \
        @react-navigation/native @react-navigation/stack \
        expo-checkbox lucide-react-native \
        react-native-gesture-handler react-native-payment-icons \
        react-native-reanimated react-native-safe-area-context \
        react-native-screens react-native-svg

Link native modules for iOS. There are no modules to link for Android.

cd ios && pod install

Android setup

Android modules are auto-linked. Rebuild your Android app after installation.

cd android && ./gradlew clean

Add TypeScript Support

Follow the official guide for Adding TypeScript to an Existing Project.

Step 2: Initialise the WestpacProvider component

Add the WestpacProvider component to your app, and initialise it with:

  • apiConfig.gateway = quickstream
  • apiConfig.merchantIdentifier = A Supplier Business Code in your QuickStream facility.
  • apiConfig.publishableKey = Your Publishable API key.
  • paymentProviders.card{} (This example collects cards.)

EXAMPLE

import { WestpacProvider } from "@westpac-developer/react-native-sdk";

export default function ExampleLayout() {
    return (
        <WestpacProvider
            apiConfig={{
                gateway: "quickstream",
                merchantIdentifier: "MYBUSINESS",
                publishableKey: "MY_PUBLISHABLE_API_KEY",
            }}
            paymentProviders={{
                card: {
                    savePaymentDetails: {
                        hidden: true
                    }
                }
            }}
        >
        </WestpacProvider>
    );
}

Step 3: Initialise the PaymentSheet component

In your app, after your user selects the goods and services they are purchasing, display a button to open the Payment Sheet UI using the PaymentSheet component.

Implement the following:

EXAMPLE

import {
    PaymentSheet,
    usePaymentSheet,
} from "@westpac-developer/react-native-sdk";
import {
    type OnPaymentFailureError,
    type PaymentSubmission,
} from "@westpac-developer/react-native-core";
import { Pressable, Text, View } from "react-native";

export default function PaymentSheetIndex() {
    const { openPaymentSheet, closePaymentSheet, isOpen } = usePaymentSheet();

    const purchaseAmount = 100; // Replace with your actual purchase amount

    return (
        <>
            <View>
                <Pressable
                    accessibilityLabel="Pay now"
                    accessibilityRole="button"
                    onPress={openPaymentSheet}
                    accessible={!isOpen}
                >
                    <Text>
                        Pay Now
                    </Text>
                </Pressable>
            </View>
            <PaymentSheet
                onPaymentSubmitted={async (payment: PaymentSubmission) => {
                    if (payment.type === "single-use") {
                        console.log(payment.token.singleUseTokenId);
                    } else {
                        console.log("Unhandled payment.type: " + payment.type);
                    }
                }}
                onPaymentFailure={async (error: OnPaymentFailureError) => {
                    console.log("code: ", error.code);
                    console.log("type: ", error.type);
                    console.log("message: ", error.message);
                    console.log("additional details?: ", error.details);
                    closePaymentSheet();
                }}
                lineItems={[
                    {
                        label: "Purchase amount",
                        amount: purchaseAmount
                    }
                ]}
            />
        </>
    );
}

Step 4: Take a payment

In the onPaymentSubmitted function, send the singleUseTokenId to your server.

  1. On your server read the single-use token from the parameter.
  2. Verify your customer.
  3. To take a one-off payment:
    1. Using your secret API key and the single-use token, send a request to take a one-time payment.
  4. Or, if you need to take more than one payment with the card details, you should register the card:
    1. Find a customer by your customer number or by the customerId.
    2. If your customer doesn't exist, create one.
    3. Using your secret API key and the single-use token, send a request to register the card.
    4. You will receive an account token. You should then take payments using the account token via this API or using batch payment file. If the customer already has an account token with the same card number, registering it again will update the expiry date and cardholder name and return the same account token.

EXAMPLE

import { router } from "expo-router";
import { type PaymentSubmission } from "@westpac-developer/react-native-core";

async function onPaymentSubmitted(payment: PaymentSubmission) {
    router.navigate({
        pathname: "/purchase-complete",
        params: { token: payment.token.singleUseTokenId }
    });
}

Step 5: Present the result

Inform the customer that they have completed the payment and present the result.

Step 6: Improve your solution

You may now improve your solution by:

Step 7: Test your integration

Refer to the test card numbers, and see Testing for more.

(Optional) Direct Debit

Update your code to provide DirectDebitProviderConfig in paymentProvider to the WestpacProvider.

EXAMPLE

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        card: {
            savePaymentDetails: {
                hidden: true
            }
        },
        directDebit: {
            savePaymentDetails: {
                hidden: true
            }
        }
    }}
>
</WestpacProvider>

If you are signing up customers for Direct Debit and will display your Direct Debit Request Service Agreement/Authority prior to opening the Payment Sheet UI:

  1. Configure Direct Debit without displaying it as an option in the Payment Sheet UI.
  2. Open the Payment Sheet to the Direct Debit payment method page directly.

EXAMPLE

In the PaymentProvidersObject, provide DirectDebitProviderConfig, and order and do not specify directDebit.

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        // Provide order, but do not provide directDebit in the order array.
        order: ["card"],
        card: {
            savePaymentDetails: {
                hidden: true
            }
        },
        // configure directDebit
        directDebit: {
            savePaymentDetails: {
                hidden: true
            }
        }
    }}
>
</WestpacProvider>

Call openPaymentSheet() and provide "DirectDebitScreen" and set backButton to false.

openPaymentSheet("DirectDebitScreen", false);

(Optional) Apple Pay

Apple Merchant ID

Obtain an Apple Merchant ID from the Apple Developer website.

Payment Processing Certificate

Sign in to the QuickStream portal and Add an iOS Certificate. This process involves:

  1. Downloading a Certificate Signing Request from QuickStream.
  2. Exchanging the CSR with Apple for a Payment Processing Certificate.
  3. Uploading the Payment Processing Certificate to QuickStream.

Integrate your app

Update your code to provide ApplePayProviderConfig in paymentProvider to the WestpacProvider.

Refer to Apple Pay in an App with QuickStream REST API.

EXAMPLE

import { SupportedNetworkEnum } from "@rnw-community/react-native-payments";
import { WestpacProvider } from "@westpac-developer/react-native-sdk";

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        card: {
            savePaymentDetails: {
                hidden: true
            }
        },
        applePay: {
            currencyCode: "AUD",
            countryCode: "AU",
            merchantIdentifier: "merchant.com.myappname",
            supportedNetworks: [
                SupportedNetworkEnum.Visa,
                SupportedNetworkEnum.Mastercard,
                SupportedNetworkEnum.Amex
            ]
        }
    }}
>
</WestpacProvider>

``

(Optional) Google Pay

Activate Google Pay

Sign in to the QuickStream portal and activate Google Pay.

Gateway Merchant ID

Take note of your QuickStream Community Code. This is the gatewayMerchantId in your integration.

Integrate your app

Update your code to provide GooglePayProviderConfig in paymentProvider to the WestpacProvider.

Refer to Google Pay in an App with QuickStream REST API.

EXAMPLE

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        card: {
            savePaymentDetails: {
                hidden: true,
            },
        },
        googlePay: {
            countryCode: "AU",
            currencyCode: "AUD",
            cardParameters: {
                allowedAuthMethods: ["PAN_ONLY", "CRYPTOGRAM_3DS"],
                allowedCardNetworks: ["VISA", "MASTERCARD", "AMEX"],
            },
            gatewayMerchantId: "COMMUNITYCODE",
            merchantInfo: {
                merchantName: "My Business",
            },
        },
    }}
>
</WestpacProvider>

(Optional) PayTo

Server-side

Refer to the PayTo with QuickStream REST API guide to integrate PayTo with your back-end.

Send the singleUseTokenId to your server.

  1. on your server read the single-use token from the parameter.
  2. Verify your customer.
  3. To take a one-off payment
    1. Using your secret API key and the single-use token, send a request to eCommerce PayTo payment.
  4. Or, if you need to take more than one payment, you should create a PayTo agreement:
    1. Find a customer by your customer number or by the customerId.
    2. If your customer doesn't exist, create one.
    3. Using your secret API key and the single-use token, send a request to create a PayTo Agreement.
    4. You will receive an agreementToken. You should then take payments using the agreement token via this API or using batch payment file.

Integrate your app

Update your code to provide PayToProviderConfig in paymentProvider to the WestpacProvider.

Example

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        card: {
            savePaymentDetails: {
                hidden: true
            }
        },
        payto: {}
    }}
>
</WestpacProvider>

(Optional) PayID

Server-side

Implement an endpoint to fetch a PayID for your customer.

Refer to the PayID with QuickStream REST API guide to integrate PayID with your back-end.

Integrate your app

Update your code to provide the PayIdProviderConfig to the WestpacProvider.

  • Provide helpUrl to tell customers how to pay by PayID.
  • Provide the PayID registered name in merchantName to match the name customers see in their banking app.

EXAMPLE

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        card: {
            savePaymentDetails: {
                hidden: true
            }
        },
        payId: {
            helpUrl: "https://www.westpac.com.au/personal-banking/online-banking/making-the-most/payid/",
            merchantName: "My Business"
        }
    }}
>
</WestpacProvider>

Fetch a PayID

Implement the onPayIdInitiation() function for the PaymentSheet to fetch a PayID for the customer from your server.

EXAMPLE

<PaymentSheet
    onPaymentSubmitted={onPaymentSubmitted}
    onPaymentFailure={onPaymentFailure}
    onPayIdInitiation={async () => {
        const { email, referenceNumber } = await generatePayId();
        return { email, referenceNumber };
    }}
    lineItems={[
        {
            label: "Purchase amount",
            amount: purchaseAmount
        }
    ]}
/>

(Optional) Custom Theming

Customise the visual theme of the Payment Sheet UI by providing styles to match the design of your app.

Provide a mode

Initialise ThemeConfig with a mode. You can choose light, dark or system (default.)

Override the theme

Customise the theme of the Payment Sheet UI by providing theme in ThemeConfig. You can customise the text, buttons, background and more.

EXAMPLE

<WestpacProvider
    themeConfig={{
        mode: "light",
        theme: {
            darkColors: {
                primary: "#da1710"
            },
            components: {
                button: {
                    primary: {
                        view: {
                            borderRadius: 10
                        }
                    }
                }
            }
        }
    }}
    apiConfig={{...}}
    paymentProviders={{...}}
>
</WestpacProvider>

(Optional) Custom Payment Methods

Display other payment methods in the Payment Sheet UI by providing one or more CustomPaymentTypeConfig in paymentProvider to the WestpacProvider.

The id property is provided in the onCustomPaymentInitiation() callback function to identify which payment method was chosen by the user. You then handle the integration and payment processing in your app.

EXAMPLE

import { type CustomPaymentTypeConfig } from "@westpac-developer/react-native-sdk";

paymentProviders={{
    order: ["card", "paypal"],
    paypal: {
        id: "paypal",
        displayName: "PayPal",
        icon: <Text>PayPal</Text>,
    } as CustomPaymentTypeConfig,
    card: {}
}}

...

<PaymentSheet
    onCustomPaymentInitiation={async (paymentId: string) => {
        // handle a custom payment method based on the paymentId argument.
        console.log(paymentId); // "paypal"
    }}
    ...
/>

(Optional) Saved Payment Methods

Display your customers' saved card and bank accounts in the Payment Sheet UI. Do this when you want your customer to choose an existing payment method for a payment, or when updating an account.

Server-side

Implement an endpoint to retrieve a list of cards or bank accounts stored on for your customer. You can implement a request list the accounts for a customer using the Customers API.

For this simple example, return JSON objects matching PaymentMethodSource.

Tips:

  • default = true when there is many accounts will display at the top.
  • For bank accounts title=Bank Account, subtitle=paymentInfo.accountNumber, maskedNumber=paymentInfo.bsb

Set Payment Methods

In your app, retrieve one or more accounts from your server and then call setSavedPaymentMethods( methods: PaymentMethodSource[] ).

import { useEffect } from "react";
import { usePaymentSheet } from "@westpac-developer/react-native-sdk";

// Inside your component:
const { setSavedPaymentMethods } = usePaymentSheet();

useEffect(() => {
    const listMethods = async () => {
        try {
            // get the accounts for customer 123456
            const resp = await fetch(
                `https://myserver.com.au/accounts/list/123456`,
                {
                    headers: {
                        "Content-Type": "application/json",
                    },
                    method: "GET",
                }
            );

            if (resp.status !== 200) {
                console.error("Could not retrieve payment methods", resp);
            }

            // this example assumes the responses are in the
            // same format as PaymentMethodSource:
            // (CustomerPaymentCreditCardModel or CustomerPaymentBankAccountModel)
            const paymentMethods = await resp.json();
            setSavedPaymentMethods(paymentMethods.data);
        } catch (err) {
            console.error(err);
        }
    };
    listMethods();
}, []);

Take a payment

In the onPaymentSubmitted function, handle retrieving the accountToken or a singleUseTokenId from the PaymentSubmission object.

You can then take payments using the account token via this API.

EXAMPLE

async function onPaymentSubmitted(payment: PaymentSubmission) {
    if (payment.type === "single-use") {
        console.log(payment.token.singleUseTokenId);
        // send the singleUseTokenId to your server to take a payment or save the account.
    } else if (payment.type === "saved") {
        console.log(payment.accountToken);
        // send the accountToken to your server to take a payment.
    }
}

(Optional) Save Payment Details Checkbox

Implement a checkbox in the Payment Sheet UI to allow your customer to choose if they want to save their card or bank account details.

Server-side

Implement an endpoint to take a payment, and then save the payment details for your customer.

  1. On your server read singleUseTokenId and customerId from the parameters.
  2. Verify your customer.
  3. Using your secret API key and the single-use token, send a request to take a one-time payment.
  4. Confirm that the transaction was successful.
  5. You will receive a receiptNumber to identify the transaction.

Register the card using the receiptNumber:

  1. Find a customer by your customer number or by the customerId.
  2. If your customer doesn't exist, create one.
  3. Using the receiptNumber, send a request to register the card.
  4. You will receive an account token.

You should then take further payments using the account token via this API or using batch payment file.

If the customer already has an account token with the same card number, registering it again will update the expiry date and cardholder name and return the same account token.

Client-side

Update your code to provide CardProviderConfig and/or the DirectDebitProviderConfig in paymentProvider to the WestpacProvider.

For each applicable config object, provide SavePaymentDetails and set hidden to false.

You can also change the label of the checkbox by providing text, and toggle the default selection of the checkbox using default.

EXAMPLE

<WestpacProvider
    apiConfig={{
        gateway: "quickstream",
        merchantIdentifier: "MYBUSINESS",
        publishableKey: "MY_PUBLISHABLE_API_KEY",
    }}
    paymentProviders={{
        card: {
            savePaymentDetails: {
                hidden: false
            }
        },
        directDebit: {
            savePaymentDetails: {
                hidden: false
            }
        }
    }}
>
</WestpacProvider>

The customer will see a checkbox and select it to indicate they want to save their payment details.

In the onPaymentSubmitted function handle when the client has selected the checkbox by inspecting the savePaymentDetails property of SingleUseTokenResponse.

EXAMPLE

import { router } from "expo-router";
import { type PaymentSubmission } from "@westpac-developer/react-native-core";

async function onPaymentSubmitted(payment: PaymentSubmission) {
    if (payment.type === "saved") {
        console.log(payment.accountToken);
        // handle the customer selecting an existing saved payment method
        // and taking a payment or updating an account using the accountToken.
    } else if (payment.type === "single-use") {
        if (payment.token.savePaymentDetails) {
            // handle taking a payment and saving the payment account details.
        } else {
            // handle taking a payment using the single-use token.
        }

        router.navigate({
            pathname: "/purchase-complete",
            params: { ... },
        });
    }
}
Westpac Privacy Statement

Privacy Statement (for individuals whose personal information may be collected - in this clause referred to as "you"). All personal information we collect about you is collected, used and disclosed by us in accordance with our Privacy Statement which is available at Privacy Statement or by calling us through your relationship manager or Westpac representative. Our Privacy Statement also provides information about how you can access and correct your personal information and make a complaint. You do not have to provide us with any personal information but, if you don't, we may not be able to process an application or a request for a product or service.