In certain scenarios, you may want to perform a zero-value authentication to verify a customer's payment method without actually charging them. This is often used for validating card details or setting up a payment method for future use.
To perform a zero-value authentication, you first need to create a Payment Session set for this purpose. You can find more details on how to do this in the Account Verification section.
Once a Payment Session for zero-value authentication has been created and you have the clientSecret, you can initialize the controller object with the appropriate configuration. Specifically, you need to set the usage option to "setup-card" when initializing the SDK.
Here's an example of how to configure the controller object for zero-value authentication:
const controller = createController({
publicKey,
clientSecret,
// accountId, // If using the Platform Fee model
usage: "setup-card"
});If the zero-value authentication is successful, the customer will not be charged, but the payment method will be validated and can be used for future transactions.
By default, the embedded SDK handles most payment flows seamlessly before the result is returned to your application. However, in certain scenarios you may want to handle specific actions in a manual way.
To configure how the embedded SDK handles required actions, you can use the manuallyHandleActions controller configuration flag. When set to true, it allows you to manage required actions manually, giving you more control over the payment process.
Here's an example of how to configure the embedded SDK to manually handle required actions:
const controller = createController({
publicKey,
clientSecret,
// accountId, // If using the Platform Fee model
manuallyHandleActions: true
});In some cases, you may want to pass some required information to the embedded SDK that is not collected at previous stages of the SDK initialisation.
This can include:
- Client Secret: if this was not available at the time of initialising the SDK;
- Customer Email: if this was not available at the time of creating the Payment Session. The
customerEmailorcustomerDetails.idis required for processing the payment. If it was not provided at the time of creating the Payment Session, then it must be provided here.
Here's an example of how to pass additional data to the embedded SDK:
form.addEventListener("submit", async (e) => {
e.preventDefault();
try {
const paymentSession = await checkout.attemptPayment({
clientSecret: 'ps_XXXXXXXXXXXXXXXX',
customerEmail: 'test@email.com'
});
handlePaymentResult(paymentSession);
} catch (error) {
// Show error to customer
}
});The example above demonstrates how to pass the clientSecret and customerEmail to the embedded SDK when attempting to process a payment. This is particularly useful if this information was not available during the initial SDK setup or Payment Session creation.
The embedded SDK provides a beforePaymentAttempt hook that allows you to execute custom logic right before a payment attempt is made. This can be useful for performing additional validations, logging, or modifying the payment data before it is sent to the server.
This hook can be set using the setBeforePaymentAttemptHandler method on the controller object. The handler function you provide will receive an event object containing details about the payment attempt, and you can perform any necessary actions before the payment is processed.
Here's an example of how to use the beforePaymentAttempt hook to validate the billing country before allowing the payment to proceed:
controller.setBeforePaymentAttemptHandler(async (event) => {
const billingAddress = event.fieldCollectionData?.billingAddress;
const country = billingAddress?.country;
console.log("Billing country:", country);
// Only allow GB addresses
if (country && country !== "GB") {
// Return an error object to prevent the payment attempt from proceeding
return { type: "error" };
}
// Return a success object to allow the payment attempt to proceed
return { type: "success" };
});If your checkout flow includes a wallet component (e.g., Apple Pay, Google Pay), you can use the dataChange hook to calculate and update the shipping costs based on the customer's selected shipping option.
When the customer selects a shipping option in the wallet, the setDataChangeHandler method allows you to listen for changes in the wallet data, including the selected shipping option. You can then calculate the appropriate shipping cost based on the selected option and update the payment session with the new total amount via the paymentsessionupdate endpoint.
Here's an example of how to use the dataChange hook to handle shipping costs in a Google Pay component. Please note that the same approach can be applied to other wallet components that support the dataChange hook:
// Initialize the Google Pay component with shipping options
const googlePay = createGooglePay(controller, {
merchantName: 'Example Merchant',
merchantCountryCode: 'GB',
// Set initial price status to `ESTIMATED`
// since the final amount will depend on the selected shipping option
priceStatus: 'ESTIMATED',
shippingConfig: {
options: [
{
id: 'standard',
label: 'Standard Shipping',
description: '5-7 business days',
},
{
id: 'express',
label: 'Express Shipping',
description: '1-2 business days',
},
],
},
});
// Listen for changes in the Google Pay data
googlePay.setDataChangeHandler(async (event) => {
if (event.changeTrigger === 'shipping-option-changed') {
// Get the selected shipping option ID from the event data
const selectedOption = event.data.currentShippingOptionId;
// Calculate the shipping cost based on the selected option
const shippingCost = await calculateShipping(selectedOption);
// Calculate the new total amount
const newTotal = baseAmount + shippingCost;
// Update the wallet with the new total amount and set price status to `FINAL`
return {
type: 'success',
data: {
transactionData: {
totalAmount: newTotal,
priceStatus: 'FINAL'
}
}
};
}
return { type: 'success' };
});The embedded SDK allows you to customize the appearance of the payment form to match your brand's look and feel. You can configure various theming options such as colors, fonts, and styles to create a cohesive checkout experience for your customers.
To customize the theme of the embedded SDK, you can use:
- the
themeconfiguration option when initializing thecontrollerto apply a theme to all components created by that controller, or - the
themeoption when creating individual components (e.g., card form, Apple Pay button, Google Pay button) to apply a theme to specific components.
const controller = createController({
publicKey,
clientSecret,
theme: {
fontFamily: 'system-ui, -apple-system, Segoe UI, Roboto, sans-serif',
baseBackground: '#ffffff',
baseBorderRadius: '8px',
textColor1: '#111827',
textColor2: '#6b7280',
},
});By customizing the theme, you can ensure that the payment form aligns with your brand identity and provides a visually appealing experience for your customers during checkout.
You can find more details on the available theming options and how to apply them in the Theming documentation page.