Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ios] Close Apple Pay sheet programmatically #447

Closed
jaaywags opened this issue Jul 21, 2021 · 16 comments · Fixed by #1164
Closed

[ios] Close Apple Pay sheet programmatically #447

jaaywags opened this issue Jul 21, 2021 · 16 comments · Fixed by #1164
Labels
blocked Don't start work on this until label is removed enhancement New feature or request

Comments

@jaaywags
Copy link

jaaywags commented Jul 21, 2021

Is your feature request related to a problem? Please describe.
I don't think so.

Describe the solution you'd like
I would like to be able to call theuseApplePay()method, and it return a method which can be used to close the Apply Pay window.

Currently, it returns 3 methods, and one property. Can we add a 4th method? Maybe called closeApplePayWindow()

Additional context
I have an application where the user can toggle between n subscription tiers. They can pay by entering their card info into the app, or choose to pay with Apple Pay.

If they choose to pay with Apple Pay, the window pops up asking which card they would like to use. Once they decide and select their card, the application sends a request to our Payment Service, with the payment id they selected. Our Payment Service will subscribe the customer to that subscription plan using the payment method. The Payment Service will return success if everything goes well.

The application is then done processing the payment. It updates the state as needed, but there is no way to close the Apple Pay window. This is normally done with the confirmApplePayPayment() function, but in our case, we did not use a PaymentIntent, and so we have no ClientSecret to pass it.

Describe alternatives you've considered
The existing implementation outlined in the example project utilizes the PaymentIntent workflow. That is not ideal for the subscription model. If I try to create a PaymentIntent, there is no way I can specify what Subscription it corresponds to. This is a problem because once the PaymentIntent succeeds, there is no way our Payment Service can determine this and provision the correct features.

A work around would be to modify our Payment Service to store the PaymentIntent Id, and what Subscription it corresponds to. We could then setup a webhook that looks this up after the PaymentIntent succeeds, but this is (to me at least) not the cleanest way. I think it would be better to implement a method returned from useApplePay(). I can call this method and it will close the Apple Pay window.

@jaaywags
Copy link
Author

I would be willing to make the code change, I just get a bit lost on how to go from stripe-react-native to the StripeSdk. I followed the call all the way down to here, but I am not sure where to go from there.

@jaaywags jaaywags changed the title Close Apple Pay Window [ios] Close Apple Pay Window Jul 21, 2021
@thorsten-stripe
Copy link
Contributor

You will need to extract the PaymentIntent from your subscription object, return that PaymentIntent's client_secret to your app and then call confirmApplePayPayment with that client_secret. The SDK will read out the state from the PaymentIntent (e.g. succeeded) and close the sheet accordingly.

@jaaywags
Copy link
Author

@thorsten-stripe Hi, thank you for getting back to me.

Creating a subscription does not always create a PaymentIntent. For example, if a customer has credit, that credit is applied to the new cost and if it covers the full amount, no additional payment is required, thus no PaymentIntent is created.

I have an example of this scenario. I attached a screenshot from my debugger. It is a very straight forward approach to create subscription and it is not creating any PaymentIntent. I confirmed this is a valid scenario with the Stripe support team today.

What do you advise we do?

Screenshot

@thorsten-stripe thorsten-stripe added enhancement New feature or request need triage labels Jul 23, 2021
@thorsten-stripe thorsten-stripe changed the title [ios] Close Apple Pay Window [ios] Close Apple Pay sheet programmatically Jul 23, 2021
@acatalina
Copy link

acatalina commented Jul 30, 2021

I've got another use case for this feature... I am confirming all my payments server side so I need to be able to call the completion block myself when I get confirmation from the server.

Edit: Forgot to mention that currently there is no way neither of programatically cancelling apple pay. Example would be: present apple pay, confirm payment, something goes wrong, UI cannot recover

@simonmitchell
Copy link

This is definitely a requirement of this SDK. What happens if our call to get a client secret from the server fails? Currently, we have to wait for the Apple Pay UI to timeout itself and disappear, we really need a way to programmatically dismiss it!

@jamiembrown
Copy link

+1 on this. Another use case is Stripe Connect. You can't currently use Direct Charges in the stripe-react-native API - but if you could cleanly close the Apple Pay Window without a Client Secret, then you could attach the payment method to your platform and charge the card server side.

Without this little feature it's actually impossible to use with Direct Charges on Stripe Connect, but with this feature it would be trivial.

@arekkubaczkowski arekkubaczkowski added the blocked Don't start work on this until label is removed label Sep 10, 2021
@shqear93
Copy link

We have the same issue, we're not able to create subscriptions on stripe!

@shqear93
Copy link

shqear93 commented Jan 14, 2022

Our case was:

  1. we set a trial period on subscription creation
  2. we want to use apple pay
  3. we can't create $0 payment intent
  4. we can't collect the payment method from apple pay
  5. so we were thinking in a workaround: getting payment method id then dismissing apple payment sheet if the user was eligible for trial period but we couldn't dismiss it

I was able to fix the issue using setup intents, so basically we create a subscription with trial free period in incomplete status (payment_behaviour = default_incomplete and default_payment_method = nil), the newly created subscription will automatically create setup intent in (subscription.pending_setup_intent) where I'm able to retrieve the setup intent by it's id and return client_secret
for the app side we followed this article to integrate confirm flow for the setup intent that created by the new subscription

@JacobJaffe
Copy link

This is definitely a requirement of this SDK. What happens if our call to get a client secret from the server fails? Currently, we have to wait for the Apple Pay UI to timeout itself and disappear, we really need a way to programmatically dismiss it!

Is there a workaround for this? Even forcing an error state would be good (I've tried via calling confirmApplePayPayment with a dummy clientSecret, but that just... crashes the app)

@innergap
Copy link

Also having this issue. Creating a subscription using the payment method id retrieved from Apple Pay button and there's no way to close the sheet after this happens without calling confirmApplePayPayment which makes another payment so that the user is charged twice.

@KeithM23
Copy link

We're also having this issue but using a hack to get around it.

On the stripe dashboard we create a Payment on Live/Test and record the client secrets generated. We then pass these known good client secrets to confirmApplePayPayment, this works / closes the popup with a done/success message.

The client secrets don't seem to expire / can be confirmed indefinitely from our experience but this could change/may not be the case so its best to use this hack with the client secrets being passed from your server so you can hot swap them if needed.

This appears to work for Stripe Connect as well, we created a payment on the Platform account and used its client secret to close the popup. We are using this for Stripe Connect when creating Shared/Cloned Customers so it may not work in other scenarios

Ideally though an actual fix for this is added as the above could break at any time

@innergap
Copy link

innergap commented Jul 14, 2022

Thanks, @KeithM23 for the work around. Worked for me on iPhone, but didn't on mac Safari.

To successfully close the sheet and create a subscription with stripe, I pass in the client secret from the backend:

  1. subscription = stripe.subscriptions.create
  2. latest_invoice = subscription.latest_invoice
  3. invoice = await stripe.invoices.retrieve(latest_invoice);
  4. payment_intent = invoice.payment_intent
  5. paymentIntent = stripe.paymentIntents.retrieve(payment_intent);
  6. client_secret = paymentIntent.client_secret;
  7. front-end confirmApplePayPayment(client_secret)

However, when I create a subscription with a coupon or trial days, it doesn't create latest_invoice and alas, I cannot use it to retrieve any payment intent client secret - and so I cannot use this method to close the sheet.

update
I erroneously thought that Safari on mac actually uses the .ios file instead of the .web file. The method that @KeithM23 provided works well for me on the iPhone! For web, ev.complete('success'); works well to close the sheet.

@ronak-safara
Copy link

@charliecruzan-stripe how does #1164 close this?

@charliecruzan-stripe
Copy link
Collaborator

With the dismissPlatformPay function

@ronak-safara
Copy link

@charliecruzan-stripe got it thank you. Any chance there's an equivalent in the iOS native library (sorry I thought this was that initially)?

@charliecruzan-stripe
Copy link
Collaborator

This is the native call that that JS function results in -> https://github.com/stripe/stripe-react-native/blob/master/ios/ApplePayViewController.swift#L59 (hopefully that answers your question)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
blocked Don't start work on this until label is removed enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.