The billing stage captures details required for payment authorization and compliance.
-
Billing address: The billing address is stored on the Cart. It is primarily used when required by your Payment Service Provider (PSP) or for regulatory compliance. If the tax mode is
Platform, Composable Commerce uses theshippingAddressfor tax calculation. If your tax strategy depends on the billing address, use theExternalorExternalAmounttax modes, or implement custom logic. -
Payment method selection: Before creating a Payment in Composable Commerce, determine the payment methods to offer the customer. Base this decision on your PSP's capabilities and your business rules.
Step 1: Handle the billing address
shippingAddress value to the billingAddress. If a different address is required, collect it through a form and validate its format.Collect a billing address only if your PSP, tax rules, or other regulations mandate it. Skipping this step creates a more streamlined user experience and can improve conversion rates.
setBillingAddress update action. When applying updates to the Cart, always use the latest version of the Cart to prevent concurrency errors.async function setBillingAddress(cartId: string, version: number, address) {
return apiRoot
.inStoreKeyWithStoreKeyValue({ storeKey })
.carts()
.withId({ ID: cartId })
.post({
body: {
version,
actions: [{ action: "setBillingAddress", address }],
},
})
.execute();
}
Step 2: Handle payment method selection
Composable Commerce does not store a catalog of payment methods from your PSPs. You must handle this in your BFF using the following logic:
- Fetch available payment methods from your PSPs.
- Apply business rules, such as country restrictions, product eligibility (for example, no Cash-On-Delivery for perishable goods), or order amount thresholds.
- Return the filtered list to the frontend for the user to select from.
If the session is interrupted, persist the user's choice using a Custom Field on the Cart. This makes the checkout flow resumable.
async function setSelectedPaymentMethod(
storeKey: string,
cartId: string,
version: number,
method: string
) {
return apiRoot
.inStoreKeyWithStoreKeyValue({ storeKey })
.carts()
.withId({ ID: cartId })
.post({
body: {
version,
actions: [
{
action: "setCustomField",
name: "selectedPaymentMethod",
value: method,
},
],
},
})
.execute();
}
When designing your BFF's payment logic, consider the following:
- Decouple from the frontend: Never expose PSP private keys or sensitive logic to the client. All PSP interactions should be handled in the backend.
- Dynamic method list: Design your system to dynamically fetch payment methods. This allows you to add options like "Buy Now, Pay Later" or new digital wallets without requiring code changes and redeployments.
- Multi-payment scenarios: Composable Commerce supports multiple Payment objects on a single Cart, enabling split payments (for example, gift card and credit card).
Key takeaways
- Collect the billing address only if required by your PSP or for regulatory compliance. The billing address is optional for tax calculation in Platform tax mode.
- Retrieve and filter payment methods through your BFF based on your PSPs and business rules. Composable Commerce does not manage payment method lists.
- Persist the selected payment method using a Custom Field on the Cart to build a resilient and resumable checkout flow.
- Design your BFF to decouple PSP logic from the frontend and support dynamic payment method lists for flexibility.
Next, we will cover payment processing and integration, where you will learn how to create a Payment, add it to the Cart, handle PSP webhooks, and manage the Cart state.