Why Shopify revokes Stripe payment methods on subscriptions
The symptom is always the same shape: customerPaymentMethodRemoteCreate
returns a payment method without complaint โ and then, when a subscription contract
tries to use it (or sometimes minutes after creation), Shopify quietly revokes it with
a reason like STRIPE_API_INVALID_REQUEST_ERROR or
STRIPE_GATEWAY_NOT_ENABLED. Renewals start failing, the docs one-liner
(“Invalid request. Failed to retrieve payment method from Stripe.”)
doesn't say why, and the forum threads asking about it have sat unanswered
for years. This guide explains the mechanism, the three causes that cover nearly
every case, and how to tell which one you have.
The mechanism: creation doesn't validate anything
customerPaymentMethodRemoteCreate takes a pair of raw Stripe IDs โ a
customer_id (cus_โฆ) and a
payment_method_id (pm_โฆ) straight from the Stripe API. Per
Shopify's own documentation, the operation is asynchronous, and the
returned payment method may initially be in an incomplete state. In
other words: nothing is checked at call time.
The real check happens later, when Shopify itself calls the Stripe API to retrieve that payment method โ typically the moment you attach it to a subscription contract, or when a billing attempt needs it. If that retrieval fails, Shopify revokes the payment method and records a revocation reason. So “our Stripe integration works” and “Shopify can retrieve it” are two different statements โ because they can be talking to two different places.
The key fact: Shopify doesn't use your API keys
When Shopify validates a remote Stripe payment method, it queries the Stripe account
that is connected to the store itself โ the connect flow described in
Shopify's subscription
migration docs โ not whatever Stripe account your app's own keys belong to. The
sibling revocation reason in the same enum spells it out:
STRIPE_RETURNED_NO_PAYMENT_METHOD โ “Make sure that the correct
Stripe account is linked.”
The three causes behind STRIPE_API_INVALID_REQUEST_ERROR
-
1. Different Stripe account. The
pm_lives on your platform's Stripe account, but the store is connected to a different one. Stripe answers “no such payment method” and Shopify revokes. This is the classic case for apps that vault cards under their own Stripe keys. -
2. Test mode vs live mode. Stripe's test and live environments are
separate namespaces โ a
pm_created with test keys does not exist for live-mode calls. If the store's Stripe connection operates in live mode and your development flow created the payment method in test mode, retrieval fails the same way. On test setups this is the most common culprit. -
3. The payment method isn't attached to that customer. The two IDs
are looked up together. A
pm_that exists but was never attached to thecus_you passed โ created via API without an attach step, or a SetupIntent that never got confirmed โ also fails retrieval.
STRIPE_GATEWAY_NOT_ENABLED: the Shopify Payments case
A separate but related trap. CustomerPaymentMethodRemoteInput accepts a
remote reference from exactly three gateways โ Stripe, Braintree, or Authorize.net,
one per call. There is no Shopify Payments variant of that input. A
card vaulted in Shopify Payments cannot be created or replaced through the
remote-create path at all, because Shopify Payments is not a “remote
gateway” in this API's model.
So on a store that runs subscriptions on Shopify Payments with Stripe not enabled as
a gateway, handing Shopify a perfectly valid Stripe pm_ gets revoked
with STRIPE_GATEWAY_NOT_ENABLED (“The Stripe payment gateway is
not enabled.”) โ validation cannot even start. That reconciles the
contradictory support answers merchants report:
- Possible: on a store where Stripe is connected as the subscriptions gateway (typically merchants who migrated in from a Stripe-billed platform), remote create with Stripe IDs is the supported path.
- Not possible: on a Shopify Payments store. The two systems do
not share a vault in this API. The supported route for customer card management
there is
customerPaymentMethodGetUpdateUrlor the customer accounts payment-methods page.
Diagnostic checklist
- Retrieve the
pm_directly from Stripe using the credentials and mode of the account the store is actually connected to โ not your app's own keys. If that call errors, Shopify's internal one does too; the revocation is the same error surfacing one step later. - Confirm which gateway the store's subscriptions actually bill through. Shopify Payments? Then remote-create with Stripe references is the wrong tool entirely โ see above.
- Check the mode. If the store's connection is live-mode and your
pm_starts life in test mode, no amount of retrying will fix it. - Verify the attach. In the Stripe dashboard, open the customer
and confirm the payment method is listed under that
cus_.
Why merchants should care (not just developers)
A revoked payment method doesn't announce itself. The subscription contract keeps its schedule, the next billing attempt fails, and unless something is watching, the subscriber silently stops paying โ the classic involuntary churn path. If your store migrated subscriptions in from a Stripe-billed platform, revocation reasons are worth monitoring as a failure class of their own: they don't respond to retries, because the card was never usable in the first place. (Our decline codes guide covers the card-side failure vocabulary.)
Where Moorly fits: Moorly connects to your existing subscription app and starts read-only โ it watches every renewal, surfaces failures the moment they happen (including the ones a retry can never fix), and shows what they cost you. Join the early-access list โ
Moorly is an independent product by Velun Labs and is not affiliated with Shopify or Stripe. API behavior described here was checked against Shopify's developer documentation in August 2026 โ always confirm against the current docs.