Problem/Motivation

CyberSource is deprecating the Secure Acceptance Hosted Checkout (SAHC) API, with a sunset date in September 2026. The commerce_cybersource module currently ships two gateways: cybersource_sahc (the deprecated offsite redirect flow) and cybersource_flex (Flex Microform v2, an onsite tokenized card-fields integration). Flex is not being deprecated, but merchants currently on SAHC have no in-module path forward once it sunsets.

CyberSource's recommended replacement for SAHC is Unified Checkout (UC), a hosted JavaScript widget that renders an all-in-one payment UI (manual card entry, with optional support for wallets and Click to Pay) and returns a transient token using the same JWT shape Flex already produces. Since the transient-token lifecycle, the PTS authorization/capture/refund/void calls, and the Payer Authentication (3DS) flow are all already implemented for Flex, Unified Checkout support is primarily a matter of:

  1. A new capture-context request format (POST /up/v1/capture-contexts vs. the existing Flex generateKey() capture-context call)
  2. A new frontend widget integration replacing the per-field Microform iframes
  3. A new gateway plugin to host the above

This issue tracks adding a cybersource_unified_checkout payment gateway plugin to the module as a sibling to cybersource_flex and cybersource_sahc, giving merchants currently on SAHC (or anyone wanting the newer widget-based UX) a supported migration path.

Steps to reproduce

N/A, this is a feature request, not a bug report. There is currently no way to use CyberSource Unified Checkout with Drupal Commerce via this module; only SAHC and Flex Microform v2 are supported.

Proposed resolution

Add a new cybersource_unified_checkout gateway plugin alongside the existing two gateways, without modifying cybersource_flex or cybersource_sahc beyond a deprecation notice on the SAHC configuration form.

Recommended approach:

  • Extract the REST/PTS logic that's currently duplicated/inline in Flex.php (createPayment(), capturePayment(), refundPayment(), voidPayment(), onNotify(), getAllowedCardNetworks(), ApiClient/MerchantConfiguration setup) into a shared abstract base class or trait. Both Flex and the new UnifiedCheckout plugin extend/use it. This avoids duplicating the payment-processing logic between the two onsite gateways.
  • Add a generateCaptureContext() method (replacing Flex's generateKey() for this plugin) that calls the Unified Checkout capture-context endpoint with the richer UC request payload (allowedPaymentTypes, captureMandate, orderInformation, etc.), rather than the minimal Flex Microform request.
  • Add a new plugin form rendering a single widget mount point (<div>) instead of per-field Microform iframes, plus a hidden transient-token field.
  • Add a new JS library that initializes the UC SDK (Accept(jwt).then(accept => accept.unifiedPayments()).then(up => up.show(...))) and on token receipt submits the checkout form, replacing the Microform field-creation/token JS used by Flex.
  • Reuse the existing flex_credit_card payment method type (the transient_token field and JWT-decoding logic in createPaymentMethod() apply identically to UC tokens) rather than introducing a new bundle, unless a clear need for separation emerges during review.
  • Reuse the existing FlexReview checkout pane and PayerAuthenticationController for 3DS, adapting the visibility checks as needed. Confirm during implementation whether UC's widget handles Payer Authentication device-data collection internally (in which case the external Cardinal setup call becomes unnecessary for this gateway) or whether the existing external flow is still required.
  • Add a deprecation notice to CyberSourceSahc::buildConfigurationForm() pointing admins toward the new Unified Checkout gateway, since SAHC itself sunsets in September 2026.

Initial scope is manual card entry only (PANENTRY). Digital wallets (Google Pay, Apple Pay, Paze) and Click to Pay require additional merchant-side EBC portal configuration and are out of scope for this issue, though the capture-context request structure should be wallet-ready (i.e. not hard-coded in a way that prevents adding wallet types later).

User interface changes

  • A new "CyberSource Unified Checkout" option appears in the payment gateway plugin list at /admin/commerce/config/payment-gateways.
  • The new gateway's configuration form exposes fields for allowed payment types, capture-mandate billing options, locale/country, and checkout display mode (embedded vs. sidebar), in addition to the merchant credentials already used by Flex.
  • On checkout, selecting this gateway renders the CyberSource-hosted Unified Checkout widget instead of the current discrete card-number/CVV/expiration fields used by Flex.
  • The existing SAHC gateway configuration form gains a deprecation notice linking to the new gateway.

API changes

  • New plugin: Drupal\commerce_cybersource\Plugin\Commerce\PaymentGateway\UnifiedCheckout (and corresponding interface).
  • New plugin form: Drupal\commerce_cybersource\PluginForm\UnifiedCheckoutForm.
  • New JS library commerce_cybersource/unified-checkout registered in commerce_cybersource.libraries.yml.
  • Likely new shared base class/trait for REST/PTS gateway logic, consumed by both Flex and UnifiedCheckout (implementation detail, not a BC break for either existing plugin's public API).
  • No changes to existing cybersource_flex or cybersource_sahc plugin APIs.

Data model changes

  • No new payment method type/bundle is anticipated, the existing flex_credit_card bundle and its transient_token field are expected to be reused, since Unified Checkout produces the same transient-token JWT shape Flex already consumes. This will be confirmed during implementation.
  • New configuration schema entries under commerce_payment.commerce_payment_gateway.plugin.cybersource_unified_checkout.
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

rszrama created an issue. See original summary.

vmarchuk’s picture

Version: 8.x-1.x-dev » 2.x-dev
Issue summary: View changes
adrianandres’s picture

Issue summary: View changes

adrianandres’s picture

Status: Active » Reviewed & tested by the community

adrianandres’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.