How to Set Up Recurring or Subscription Payments in Adyen Salesforce Commerce Cloud

The Adyen Salesforce Commerce Cloud cartridge enables recurring payments by storing shopper payment methods as tokens via zero-auth requests and reusing them on subsequent checkouts with the CARD_ON_FILE processing model.

The adyen/adyen-salesforce-commerce-cloud repository provides a complete subscription payment flow through its SFRA cartridge, allowing merchants to securely store customer cards and process future transactions without repeated authentication. This implementation relies on Adyen's tokenization service to generate recurring references that persist within Salesforce Commerce Cloud payment instruments.

Enable One-Click Payments in Business Manager

Recurring functionality is controlled by the AdyenOneClickEnabled custom preference, which toggles the entire one-click payment workflow. When enabled, the checkout interface displays a "Save this card" checkbox and the backend begins utilizing the CARD_ON_FILE processing model for tokenized transactions.

Configure the AdyenOneClickEnabled Preference

In src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenConfigs.js, the system reads the preference value:

// Returns the custom preference that toggles one-click (recurring) support
getAdyenRecurringPaymentsEnabled() {
    return getCustomPreference('AdyenOneClickEnabled');
}

This preference is exposed in Business Manager under Adyen Settings → One-Click. When set to true, the cartridge activates both the frontend UI components and the backend logic required for recurring payment processing.

Store Payment Methods Using Zero-Auth

To tokenize a payment method, the cartridge executes a zero-auth request—a standard payment call with an amount of 0 that verifies the card and generates a recurring token. This occurs when the shopper checks the "Save this card" option during checkout.

The implementation in src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/adyenZeroAuth.js constructs the request:

const zeroAuthRequest = AdyenHelper.createAdyenRequestObject(
    'recurringPayment-account',
    'recurringPayment-token',
    paymentInstrument,
    customer.getProfile().email,
);

zeroAuthRequest.amount = { currency: session.currency.currencyCode, value: 0 };
zeroAuthRequest.storePaymentMethod = true;
zeroAuthRequest.recurringProcessingModel = constants.RECURRING_PROCESSING_MODEL.CARD_ON_FILE;

The Adyen response includes additionalData['recurring.recurringDetailReference'], which represents the unique token. The cartridge persists this reference on the SFCC payment instrument's custom attributes via helper methods in adyenHelper.js, enabling future retrieval during subsequent purchases.

Process Subsequent Orders with Stored Tokens

When a returning shopper selects a saved card, the frontend includes storedPaymentMethodId in the payment state data. The backend logic in src/cartridges/int_adyen_SFRA/cartridge/adyen/utils/adyenHelper.js detects this identifier and configures the request accordingly:

// If a storedPaymentMethodId is present, set the recurring model and interaction type
if (stateData.paymentMethod?.storedPaymentMethodId) {
    stateData.recurringProcessingModel = constants.RECURRING_PROCESSING_MODEL.CARD_ON_FILE;
    stateData.shopperInteraction = constants.SHOPPER_INTERACTIONS.CONT_AUTH;
} else {
    stateData.shopperInteraction = constants.SHOPPER_INTERACTIONS.ECOMMERCE;
}

The createAdyenRequestObject function automatically applies these parameters when building the checkout request. The payment is then processed via AdyenHelper.executeCall(constants.SERVICE.PAYMENT, ...), charging the stored token without requiring fresh 3D Secure authentication or card details re-entry.

Manage Recurring Payment Tokens

The cartridge provides maintenance utilities to keep stored payment methods synchronized and removable when necessary.

Delete Expired or Invalid Tokens

To remove a stored payment method, src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/adyenDeleteRecurringPayment.js interfaces with Adyen's Recurring-Disable service:

const { deleteRecurringPayment } = require('*/cartridge/adyen/scripts/payments/adyenDeleteRecurringPayment');

function removeSavedCard(customerId, token) {
    return deleteRecurringPayment({
        Customer: customerId,
        RecurringDetailReference: token
    });
}

This script requires the shopperReference (customer ID) and recurringDetailReference (token) to permanently delete the payment method from Adyen's platform.

Synchronize Wallet with Adyen

The src/cartridges/int_adyen_SFRA/cartridge/adyen/scripts/payments/updateSavedCards.js script maintains consistency between the local SFCC wallet and Adyen's stored payment methods:

const { updateSavedCards } = require('*/cartridge/adyen/scripts/payments/updateSavedCards');

function syncCustomerCards(customer) {
    return updateSavedCards({ CurrentCustomer: customer });
}

This synchronization fetches the current list of one-click payment methods from Adyen and rebuilds the SFCC wallet, ensuring expired cards are removed and new tokens are properly registered. Merchants typically invoke this via scheduled jobs or post-checkout hooks when recurring payments are enabled.

Summary

  • Enable recurring functionality by setting AdyenOneClickEnabled to true in Business Manager, which activates the one-click payment flow throughout the cartridge.
  • Store new payment methods using zero-auth requests (adyenZeroAuth.js) with recurringProcessingModel set to CARD_ON_FILE and amount set to 0.
  • Reuse stored tokens on subsequent orders by passing storedPaymentMethodId in state data, which triggers createAdyenRequestObject to set recurringProcessingModel and shopperInteraction to ContAuth.
  • Maintain token hygiene using delete (adyenDeleteRecurringPayment.js) and synchronize (updateSavedCards.js) operations to handle expired or invalidated payment methods.

Frequently Asked Questions

What is the difference between one-click and standard recurring payments in the Adyen cartridge?

The Adyen Salesforce Commerce Cloud cartridge implements one-click payments as its recurring solution, where the shopper actively selects a saved card during checkout rather than the merchant initiating charges independently. This uses the CARD_ON_FILE processing model and ContAuth shopper interaction, requiring the customer to be present for the transaction while avoiding re-entry of card details.

How does the zero-auth flow secure payment method storage?

The zero-auth flow sends a verification request with amount value 0 to Adyen via adyenZeroAuth.js, which validates the card without charging it. Upon success, Adyen returns a recurringDetailReference token that the cartridge stores on the payment instrument. This token represents a secure, PCI-compliant reference that can be used for future transactions without exposing actual card numbers.

Where are recurring payment tokens stored in Salesforce Commerce Cloud?

Recurring tokens are stored as custom attributes on SFCC payment instruments within the customer's wallet. The adyenHelper.js file manages persistence of the recurringDetailReference value, linking the local payment instrument to the corresponding stored payment method in Adyen's vault. This allows the system to retrieve and display saved cards while maintaining PCI DSS compliance.

How do I disable recurring payments for specific customers?

To disable recurring capabilities, set the AdyenOneClickEnabled preference to false in Business Manager, which hides the "Save this card" option in the UI. For individual token removal, invoke the deleteRecurringPayment function from adyenDeleteRecurringPayment.js with the customer's shopper reference and the specific token ID, which calls Adyen's Recurring-Disable API to permanently remove the stored payment method.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →