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: Initialise the WestpacProvider component
Add the WestpacProvider component to your app, and initialise it with:
apiConfig.gateway=quickstreamapiConfig.merchantIdentifier= A Supplier Business Code in your QuickStream facility.apiConfig.publishableKey= Your Publishable API key.paymentProviders.card{}(This example collects cards.)
EXAMPLE
import { type WestpacProvider } from "@westpac-developer/sdk";
export default function ExampleLayout() {
return (
<WestpacProvider
apiConfig={{
gateway: "quickstream",
merchantIdentifier: "MYBUSINESS",
publishableKey: "MY_PUBLISHABLE_API_KEY",
}}
paymentProviders={{
card: {
savePaymentDetails: {
hidden: true
}
}}
>
</WestpacProvider>
);
}
apiConfig.environment = "dev" (default when not provided.)
Step 2: 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:
- An
onPaymentSubmittedfunction that takes aPaymentSubmissionas a parameter. - An
onPaymentFailurefunction that accepts aOnPaymentFailureErrorobject as a parameter. - An array of
LineItem, where the total amount displayed in the Payment Sheet UI is calculated based on the summed amount of each item.
EXAMPLE
import {
type OnPaymentFailureError,
PaymentSheet,
usePaymentSheet,
} from "@westpac-developer/sdk";
import { Pressable, Text, View } from "react-native";
export default function PaymentSheetIndex() {
const { togglePaymentSheet, isOpen } = usePaymentSheet();
return (
<>
<View>
<Pressable
accessibilityLabel="Pay now"
accessibilityRole="button"
onPress={togglePaymentSheet}
accessible={!isOpen}
>
<Text>
Pay Now
</Text>
</Pressable>
</View>
<PaymentSheet
onPaymentSubmitted={async (payment: PaymentSubmission) => {
console.log(payment.token.singleUseTokenId);
}}
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 3: Take a payment
In the onPaymentSubmitted function, send the singleUseTokenId to your server.
- On your server read the single-use token from the parameter.
- Verify your customer.
- To take a one-off payment:
- Using your secret API key and the single-use token, send a request to take a one-time payment.
- Or, if you need to take more than one payment with the card details, you should register the card:
- Find a customer by your customer number or by the
customerId. - If your customer doesn't exist, create one.
- Using your secret API key and the single-use token, send a request to register the card.
- 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.
- Find a customer by your customer number or by the
EXAMPLE
async function onPaymentSubmitted(payment: PaymentSubmission) {
router.navigate({
pathname: "/purchase-complete",
params: { token: payment.token.singleUseTokenId }
});
}
Step 4: Present the result
Inform the customer that they have completed the payment and present the result.
- See Process a transaction using a single-use-token for more.
- The response contains the result of the payment.
- Use the
statusthat you received in your transaction response to present the result
Step 5: Improve your solution
You may now improve your solution by:
- Avoiding duplicates by using an
Idempotency-Keyheader. - Handling errors server side.
- Handling errors client side using the
onPaymentFailurefunction. - Adding additional payment methods (see the optional steps below.)
- Styling the Payment Sheet UI using Custom Theming.
- Implement a Save Payment Details Checkbox.
- Display saved cards or bank accounts using Saved Payment Methods.
- Handling a service outage.
Step 6: Test your integration
Refer to the test card numbers, and see Testing for more.
apiConfig.environment = "prod".
(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:
- Configure Direct Debit without displaying it as an option in the Payment Sheet UI.
- 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 not do provide directDebit.
order: ["card"],
card: {
savePaymentDetails: {
hidden: true
}
},
// configure directDebit
directDebit: {
savePaymentDetails: {
hidden: true
}
}
}
>
</WestpacProvider>
Call openPaymentSheet() and provide DirectScreenType.DirectDebitScreen and set backButton to false.
openPaymentSheet(DirectScreenType.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:
- Downloading a Certificate Signing Request from QuickStream.
- Exchanging the CSR with Apple for a Payment Processing Certificate.
- 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";
...
<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.
- on your server read the single-use token from the parameter.
- Verify your customer.
- To take a one-off payment
- Using your secret API key and the single-use token, send a request to eCommerce PayTo payment.
- Or, if you need to take more than one payment, you should create a PayTo agreement:
- Find a customer by your customer number or by the
customerId. - If your customer doesn't exist, create one.
- Using your secret API key and the single-use token, send a request to create a PayTo Agreement.
- You will receive an
agreementToken. You should then take payments using the agreement token via this API or using batch payment file.
- Find a customer by your customer number or by the
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
helpUrlto tell customers how to pay by PayID. - Provide the PayID registered name in
merchantNameto 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
paymentProviders={{
order: ["card", "paypal"],
paypal: {
id: "paypal",
displayName: "PayPal",
icon: <Text>PayPal</Text>,
} as CustomPaymentTypeConfig,
card: {}
}}
...
async function onCustomPaymentMethodSelected( id: string ) {
// handle a custom payment method based on the id argument.
console.log(id); // "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[] ).
{
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.
- On your server read
singleUseTokenIdandcustomerIdfrom the parameters. - Verify your customer.
- Using your secret API key and the single-use token, send a request to take a one-time payment.
- Confirm that the transaction was successful.
- You will receive a
receiptNumberto identify the transaction.
Register the card using the receiptNumber:
- Find a customer by your customer number or by the
customerId. - If your customer doesn't exist, create one.
- Using the
receiptNumber, send a request to register the card. - 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
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: { ... },
});
}
}