stripe icon indicating copy to clipboard operation
stripe copied to clipboard

Payment Sheet fails to open with Direct Charges (stripeAccount) in v7.2.0

Open PaulliDev opened this issue 4 months ago • 4 comments

Platform

  • [ ] Web
  • [X] iOS
  • [ ] Android (untested)

Describe the bug Payment Sheet fails to open (immediate “There was an unexpected error — try again in a few seconds”) when the PaymentIntent is created as a Direct Charge (using stripeAccount to act in a connected account). If I switch to Destination Charge (no stripeAccount, use transfer_data.destination, and a platform Customer), Payment Sheet works fine. This suggests the plugin doesn’t handle PIs/EKs created in a connected account context.

To Reproduce

  1. Create a connected account with card_payments + transfers active.
  2. Create a Customer inside the connected account and store its id (one per buyer×merchant).
  3. Server: create a PaymentIntent in the connected context (Direct Charge), and an Ephemeral Key for the same connected Customer and account:
// Server (Node, stripe-node)
const paymentIntent = await stripe.paymentIntents.create(
  {
    amount: 10000,
    currency: 'eur',
    customer: connectedCustomerId,                // cus_... in connected acct
    automatic_payment_methods: { enabled: true }, // also repros if ['card']
    description: 'Test direct charge'
  },
  { stripeAccount: merchantAccountId }            // <-- connected account context
);

const ephemeralKey = await stripe.ephemeralKeys.create(
  { customer: connectedCustomerId }
  {
    stripeAccount: merchantAccountId, // <-- connected account context again
    apiVersion: '2023-10-16' // mobile SDK API version
  }
);

// Then in App:
await Stripe.createPaymentSheet({
  merchantDisplayName: 'Test',
  customerId: connectedCustomerId,
  customerEphemeralKeySecret: ephemeralKey.secret,
  paymentIntentClientSecret: paymentIntent.client_secret,
  enableApplePay: false,
  enableGooglePay: false
});

await Stripe.presentPaymentSheet(); // => immediately fails with generic error

Now if you swap to Destination Charge for the same flow (no stripeAccount; use platform Customer, add transfer_data.destination and optional application_fee_amount). Payment Sheet opens and works.

Expected behavior Payment Sheet should open and allow entering a card for a brand-new connected Customer, the same way it does in the Destination Charge flow. At minimum if Direct Charges aren’t supported the plugin should surface a clear error.

Screenshots N/A (Payment Sheet crashes immediately and in console we're left with “unexpected error” toast).

Error in the console doesnt give any information (the log itself comes from paymentSheetFailed event listener): Image

The most it does it points to this line in user-script:2 Image

Additional context Testing on Real iPhone 14 Pro (ios 18.1.1) and on iPhone 15 Pro (ios 17.4) in Simulator, both with the same results. Im using the newest version of the package 7.2.0.

Usage Product In development.

Product Name: Product URL : Using Function:

  • [X] Payment Sheet / Payment Flow
  • [X] Apple Pay
  • [X] Google Pay
  • [X] Identity (@capacitor-community/stripe-identity)

PaulliDev avatar Aug 28 '25 15:08 PaulliDev

The failure with direct charges comes from how stripeAccount is handled

  • The plugin only allows to set stripeAccount once during Stripe.initialize().
  • For direct charges it must be set per PaymentIntent/Customer, but in PaymentSheetExecutor.swift the PaymentSheet(...) call never gives you an option to update stripeAccount value using STPAPIClient.shared.stripeAccount.
  • This means the SDK looks in the wrong account and the PaymentSheet fails.

Fix proposal:

iOS

  • Allow createPaymentSheet() to accept a stripeAccount param.
  • Create a per-flow STPAPIClient(publishableKey:), set client.stripeAccount = <acct_…>, and inject it via PaymentSheet.Configuration.apiClient before instantiating PaymentSheet. Its possible according to https://stripe.dev/stripe-ios/stripepaymentsheet/documentation/stripepaymentsheet/paymentsheet/configuration-swift.struct
  • Therefore no global state change needed, stripeAccount set during init stays as it was and no other processes should be affected

Android

  • Allow createPaymentSheet() to accept a stripeAccount param.
  • This works differently than iOS, Unfortunately we cannot define apiClient context per Payment Sheet here according to docs (at least as far as I found) https://stripe.dev/stripe-android/paymentsheet/com.stripe.android.paymentsheet/-payment-sheet/index.html
  • So instead we would need to temporarily re-init the global SDK context with that account using PaymentConfiguration.init(context, publishableKey, stripeAccountId) right before presenting the sheet, and restore the previous value after the flow completes.

Open questions or feedback welcome

PaulliDev avatar Aug 29 '25 11:08 PaulliDev

@PaulliDev Thanks for opening this issue and for the detailed investigation.

Just to make sure I’m understanding correctly: the problem isn’t that PaymentSheet has a bug, but rather that you want to switch the stripeAccount per payment flow, and the current plugin design only allows it to be set once during Stripe.initialize(). Because of that limitation, Direct Charges cannot work as expected — is that interpretation correct?

Let me know if my understanding aligns with your intent.

rdlabo avatar Nov 20 '25 05:11 rdlabo

@rdlabo Yes, you're correct. At the time it seemed like a bug in my mind, once you learn why its failing you realize its missing feature. Thanks for updating the ticket

PaulliDev avatar Nov 22 '25 12:11 PaulliDev

@PaulliDev The first important thing is whether this approach is actually the right one. I looked through the official React Native implementation, but I wasn’t able to find anything similar.

Unfortunately, I can’t determine whether your proposal might introduce potential issues in the future—for example, conflicts with upcoming changes in the official SDK. It does feel a bit like a workaround.

I feel it might be best to first ask in the stripe/ios and stripe/android issues about the recommended practice for switching accounts per payment. If any additional official materials are provided, I would be happy to review them. What do you think?

rdlabo avatar Nov 25 '25 06:11 rdlabo