feat: add Amazon Pay subscriptions support#11283
Conversation
Test the buildOption 1. Jetpack Beta
Option 2. Jurassic Ninja - available for logged-in A12s🚀 Launch a JN site with this branch 🚀 ℹ️ Install this Tampermonkey script to get more options. Build info:
Note: the build is updated when a new commit is pushed to this PR. |
|
Size Change: +381 B (0%) Total Size: 955 kB
ℹ️ View Unchanged
|
There was a problem hiding this comment.
Pull request overview
This PR adds end-to-end support for using Amazon Pay as a reusable payment method for subscriptions, including creation via Express Checkout, storage as a token, and use in renewals and admin flows.
Changes:
- Introduces an Amazon Pay reusable token type and wires it into the token service, payment method constants, and My Account display so Amazon Pay sources can be stored and reused for subscription renewals.
- Extends the subscriptions trait and subscription edit UI to handle multiple reusable WCPay gateways (card and Amazon Pay), including gateway-specific hooks, token selection per gateway, and Express Checkout–created subscriptions.
- Updates Express Checkout and checkout flows to support confirmation-token-based SetupIntents (especially for $0 subscription orders), including client-side confirmation, backend intent creation, and robust handling of zero-amount subscription trials.
Reviewed changes
Copilot reviewed 28 out of 29 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| woocommerce-payments.php | Bumps plugin version to 10.6.0 so server-side features (fees, Amazon Pay) are enabled for this build. |
| includes/class-wc-payments.php | Registers the new Amazon Pay token class and ensures the token service is available for the new payment method. |
| includes/constants/class-payment-method.php | Adds the AMAZON_PAY payment method constant used throughout the gateway, token, and ECE logic. |
| includes/class-wc-payments-token-service.php | Treats Amazon Pay as a reusable method: maps it to its split gateway, creates WC_Payment_Token_WCPay_Amazon_Pay instances, includes it in retrievable types, and customizes My Account display. |
| includes/class-wc-payments-order-service.php | Extends intent status handling to cover REQUIRES_CONFIRMATION and improves zero-amount SetupIntent flows by marking payments started and completing free-trial subscription orders correctly. |
| includes/class-wc-payment-token-wcpay-amazon-pay.php | Implements a dedicated Amazon Pay token type with redacted email storage and an Amazon-Pay-specific display name for saved methods. |
| includes/core/server/request/class-create-setup-intention.php | Adds metadata support (including description from order number) for unconfirmed SetupIntent creation used with confirmation tokens. |
| includes/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.php | Generalizes subscription hooks to all reusable WCPay gateways, adds Amazon Pay to the reusable list, routes Express Checkout Amazon Pay subscriptions to the split gateway, supports gateway-specific token lists, and updates admin/payment meta rendering and validation accordingly. |
| includes/class-wc-payment-gateway-wcpay.php | Changes zero-amount subscription processing to use unconfirmed SetupIntents with confirmation tokens, stores the actual payment method on the order, refines frontend-confirmation redirects (including confirmation token), and updates change-payment-method flows to handle REQUIRES_CONFIRMATION. |
| includes/express-checkout/class-wc-payments-express-checkout-button-helper.php | Centralizes detection of subscription products/carts in a helper method reusable by both the handler and JS config. |
| includes/express-checkout/class-wc-payments-express-checkout-button-handler.php | Delegates subscription detection to the helper, ensures subscription presence is reflected in JS params, and reuses that for auth and shipping decisions. |
| includes/class-payment-information.php | Makes confirmation-token detection more robust by guarding against empty payment method values. |
| client/subscription-edit-page/types.d.ts | Extends the subscription payment-method selector types to include a gatewayId so tokens can be filtered per gateway. |
| client/subscription-edit-page/index.tsx | Adds gateway-aware token caching and fetching, ensures the selector works per gateway (card vs Amazon Pay), and threads gatewayId through to the React component and bootstrap data. |
| client/subscription-edit-page/tests/index.test.tsx | Updates tests for the new gatewayId prop and multi-gateway token cache and adds coverage for the updated fetch helper signature. |
| client/express-checkout/utils/index.ts | Replaces ad-hoc setupFutureUsage logic with a reusable getStripeElementsMode helper that switches Elements between payment and subscription modes based on the current context. |
| client/express-checkout/utils/checkPaymentMethodIsAvailable.tsx | Uses getStripeElementsMode when probing availability so subscription contexts initialize Elements in subscription mode while still respecting confirmation-token options. |
| client/express-checkout/utils/tests/index.test.js | Adjusts unit tests to validate getStripeElementsMode behavior instead of the removed getSetupFutureUsage. |
| client/express-checkout/index.js | Updates the main Express Checkout JS to use getStripeElementsMode and simplifies confirmation-token Elements options to rely on paymentMethodTypes only. |
| client/express-checkout/blocks/components/express-checkout-container.js | Mirrors the Elements mode and options changes for block-based Express Checkout rendering. |
| client/express-checkout/tests/tokenized-express-checkout--product-page.test.js | Verifies that subscription contexts now use subscription mode (instead of payment + setupFutureUsage) when initializing the Tokenized Express Checkout Element. |
| client/checkout/api/index.js | Extends the intent-confirmation hash format to carry an optional confirmation token and, for SetupIntents, uses stripe.confirmSetup with that token before falling back to handleNextAction. |
| tests/unit/test-class-wc-payments-token-service.php | Adds coverage for creating Amazon Pay tokens with or without email and confirms redaction and gateway ID behavior. |
| tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-trait.php | Confirms that Amazon Pay subscription hooks are registered for scheduled payments and failing-payment updates on the split gateway. |
| tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-process-payment.php | Updates zero-dollar subscription + confirmation-token tests to assert use of Create_Setup_Intention, omission of token creation at that stage, and the new redirect hash format and order status semantics. |
| tests/unit/subscriptions/test-class-wc-payment-gateway-wcpay-subscriptions-non-reusable-methods.php | Adds tests ensuring Express Checkout Amazon Pay subscriptions are assigned to the Amazon Pay split gateway and remain automatic, while Google Pay subscriptions remain on the base gateway. |
| tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-helper.php | Exercises the new has_subscription_product helper method across product/cart/checkout contexts. |
| tests/unit/express-checkout/test-class-wc-payments-express-checkout-button-handler.php | Updates handler tests to rely on the helper’s has_subscription_product method when deciding whether shipping is required. |
| changelog/feat-amazon-pay-subscriptions-support | Documents the feature addition for Amazon Pay subscriptions as a patch-level changelog entry. |
Comments suppressed due to low confidence (1)
client/subscription-edit-page/tests/index.test.tsx:515
- The
fetchUserTokenstest that verifies "sends correct request parameters" currently assertsaction,nonce, anduser_id, but does not check the newgateway_idparameter that is now required by the AJAX handler. Adding an assertion forformData.get( 'gateway_id' )here would ensure the test fully covers the request shape expected byajax_get_user_payment_tokens.
test( 'sends correct request parameters', async () => {
let capturedUrl = '';
let capturedOptions: RequestInit | undefined;
global.fetch = jest.fn().mockImplementation( ( url, options ) => {
capturedUrl = url;
capturedOptions = options;
return Promise.resolve( {
ok: true,
json: () => Promise.resolve( { data: { tokens: [] } } ),
} );
} );
await fetchUserTokens(
123,
'http://test.com/ajax',
'test-nonce',
'woocommerce_payments'
);
expect( capturedUrl ).toBe( 'http://test.com/ajax' );
expect( capturedOptions?.method ).toBe( 'POST' );
const formData = capturedOptions?.body as FormData;
expect( formData.get( 'action' ) ).toBe(
'wcpay_get_user_payment_tokens'
);
expect( formData.get( 'nonce' ) ).toBe( 'test-nonce' );
expect( formData.get( 'user_id' ) ).toBe( '123' );
} );
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
tests/unit/test-class-wc-payment-gateway-wcpay-subscriptions-trait.php
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
For posterity: My previous point was to lean into using the token type to associate tokens with specific payment methods instead of gateway IDs.
I spent a few hours on this last week, and even though it is more than possible, it does not yield the benefits that I expected. My expectation was that we'd need much fewer changes to the methods in the subscriptions trait, but 99% of them still had to remain in place. On the other hand, we'd need to add further logic in a few places that would make the code even more convoluted, rather than less.
The SEPA issues I mentioned are also not something that I can really describe, and looking at the code in its current shape, those are not a blocker.
I've marked my previous comments as resolved.
I dove deeper, and it looks good overall. I have a few comments, all of them being essentially nitpicks. However, great work here! This is a gargantuan effort, and we're almost there!
Here are my comments so far, just after looking at the changes. I'll continue with testing now. Update: Testing worked flawlessly.
includes/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.php
Outdated
Show resolved
Hide resolved
includes/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.php
Outdated
Show resolved
Hide resolved
includes/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.php
Show resolved
Hide resolved
includes/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.php
Outdated
Show resolved
Hide resolved
Co-authored-by: Radoslav Georgiev <rageorgiev@gmail.com>
RadoslavGeorgiev
left a comment
There was a problem hiding this comment.
Looks perfect, thank you for addressing my feedback! ![]()
|
I'm going to try to review it tomorrow, but please don't hold this because of me. |
Yes, it's to indicate that the button is going to be connected to the Amazon Sandbox. Thanks for checking in! |

Fixes WOOPMNT-5663
Changes proposed in this Pull Request
Dependent on #11267 & #11278
Adding support to subscriptions for Amazon Pay, similar to Google Pay/Apple Pay.
Some high-level explanation for the changes: for the flow with Confirmation Tokens, things have changed a bit. We need to create an unconfirmed SetupIntent. Stripe's SetupIntent API doesn't support Confirmation Tokens the same way PaymentIntents do, it needs to be "unconfirmed" because the SI is created without a payment method.
Instead, we create the SetupIntent without a payment method, and the front-end calls
confirmSetup()with the Confirmation Token. Stripe then converts the Confirmation Token into a Payment Method and attaches it to the SetupIntent.Compared to the payment method flow, we were able to create and confirm the SetupIntent with the payment method attached in one backend call.
The flow is different because of how confirmation tokens work - Stripe requires front-end confirmation, because the confirmation token is short-lived and is attached to the customer's session (Stripe verifies ownership).
I needed to change the
includes/compat/subscriptions/trait-wc-payment-gateway-wcpay-subscriptions.phptrait to have theajax_get_user_payment_tokenssupport both card and non-card tokens, like the Amazon Pay ones.For this reason, changes have been made to the JS as well.
I needed to add a separate token type for this, I couldn't reuse the CC token, since Amazon Pay is a separate payment method type.
All "Amazon Pay" saved payment methods appear in Stripe as just "Amazon Pay".

There is no way to identify the type of payment (card, store card, etc.).
So I added the billing email, at least 🤷
Testing instructions
Prerequisites
npm run update-fees-fixtures && npm run up)US10.6.0, so that the server will return feeswp option update _wcpay_feature_amazon_pay 1)Customer-facing testing
Merchant-facing testing
Subscriptions management
npm run changelogto add a changelog file, choosepatchto leave it empty if the change is not significant. You can add multiple changelog files in one PR by running this command a few times.Post merge