#Aleksey-pmd-apple-pay

1 messages · Page 1 of 1 (latest)

warm heathBOT
marsh torrent
#

but do they both need to be registered with Stripe in particular or
Yes, with Stripe

#

do they need to be registered in the same account
Yes, in the account you're trying to use

orchid stump
marsh torrent
#

Other configurations might show the button depending on the details, but you wont be able to complete payment unless all those piece are properly in place

#

Depends on how you collect payments, eg using connect or not

#

Do you use direct charges via Connect?

orchid stump
#

I don't think we use Connect for out primary account, but let me double check that

#

While I get confirmation for that, I'm guessing what we've discussed so far means that the button showing up but not working isn't necessarily a bug, is it? It's up to us to determine whether or not to initialize PaymentRequest depending on where our widget is embedded, right?

#

It seems we do use Connect for our nonprofit account

marsh torrent
#

If you can share a snippet of how you initialize Stripe.js and the connected account ID you're using and I check the domains configured

orchid stump
#

Well, we use the React components for the front end and Rails for the backend. We send the foundation key to the React app from the Rails view and initialize the standard way

import { Elements, useStripe, useElements } from '@stripe/react-stripe-js'
import App from './App'
...
const StripeInner = props => {
  const stripe = useStripe()
  const elements = useElements()

  return stripe ? <App {...props} stripe={stripe} elements={elements} /> : null
}
...
const StripeOuter = ({ stripePromise, stripeFonts, ...props }) =>
  <Elements
    stripe={stripePromise}
    options={{
      locale: props.i18n.locale,
      fonts: stripeFonts,
      ...
    }}
  >
    <StripeInner {...props} />
  </Elements>

export default StripeOuter
#

Then to initialize PaymentRequest it looks something like this

    const sameOrigin = (() => {
      try {
        return location.origin && location.origin == top.location.origin
      } catch (e) {
        return false
      }
    })()
    // Disable Apple Pay cross origin for now because of Stripe bugs
    if (!sameOrigin && typeof ApplePaySession != 'undefined') {
      paymentRequest.current = 'something to prevent an infinite loop'
      setTimeout(() => setCanMakePayment(null), 0)
    } else {
      paymentRequest.current = stripe.paymentRequest({
        country:            'US',
        requestPayerName:   true,
        requestPayerEmail:  true,
        requestPayerPhone:  !!collect_phone, // must be boolean
        ...getPaymentRequestProps(),
      })
      paymentRequest.current.canMakePayment().then(setCanMakePayment)
    }
  }
#

On the Rails side, when we create the charge object, we use the headers to connect to the foundation account
{ stripe_account: Rails.configuration.stripe[:foundation_account_id] }

#

And the charge creation code looks something like this

      if self.stripe_subscription?
        self.stripe_subscription = StripeSubscription.create_by_order!(self, self.stripe_plan)
        self.current_period_start = self.stripe_subscription.current_period_start
        self.current_period_end = self.stripe_subscription.current_period_end
      else
        charge_obj = Stripe::Charge.create(
          charge_params,
          StripeAccount.stripe_headers(foundation, crowdfund?)
        )
        self.processing_id = charge_obj.id
      end
    end
marsh torrent
#

How do you init stripePromise for StripeOuter?

#

If you're using stripe_account server side for direct-charge flows, you need to ensure you're doing the same with Stripe.js when you init:
loadStripe('pk_test_plat_1234', {stripeAccount: 'acct_456_connected'})
eg

orchid stump
#

The entry point with the relevant parts looks like this

...
import React from 'react'
import { loadStripe } from '@stripe/stripe-js'
import mountReactApp, { root } from 'src/utils/mountReactApp'
import StripeWrapper from 'src/widgets/donate_v6/StripeWrapper'
...
const transformProps = ({
  stripeKey, tipping, tip_rates, payment_method, payment_methods,
  ...props
}) => {
  const stripePromise = loadStripe(stripeKey)
...
  const transformedProps = {
    ...props,
    stripePromise,
...
  }
...
  return { ...transformedProps, renderPluginHook }
}

mountReactApp(StripeWrapper, transformProps)
marsh torrent
#

Yea, you don't have that stripeAccount option

#

But I suppose that depends more on how your flow works etc and whats not working

#

This is working for you generally, though, you say, right?

orchid stump
#

Hmm, so I think we don't use the main account key when initializing at all

    beneficiary_type == 'Crowdfund' ?
      Rails.configuration.stripe[:crowdfund_publishable_key] :
      Rails.configuration.stripe[:publishable_key]
  end
#

Yes, this setup works for Apple Pay when the form is opened directly in the browser or when it's embedded on our own domain

marsh torrent
#

Can you share a specific connected account ID I can look at for the domain registration?

orchid stump
#

To explain the example where we had a partner who is also a Stripe customer embedding our form, our foundation receives donations from people and then redistributes it to the nonprofits that people want to donate to. Our partner is collecting the donations through our form for the same nonprofits we are, so the donations never go to the partner. It just so happens that this partner also has a Stripe account and a few Apple Pay donations went through when our form was embedded on their site

#

But when we tested it, it didn't work

#

This is our foundation stripe key pk_live_3vwsKhxn6eAf1Ue4khqqxpab

#

All the nonprofit donations (99.9+%) go to this account initially

marsh torrent
#

Is there a public site I can visit to see this working / not working more concretely?

orchid stump
#

This one is on our website so Apple Pay works there

#

Our partners and some of the nonprofits like to embed these donation forms on their websites as well, and that's where things started going wrong when cross domain Apple Pay was enabled after Safari 17 was released

#

Evite is the partner I mentioned who has a Stripe account and where some Apple Pay donations have come through but it didn't work for us when we tested it. Here's an Evite event, for example. However, we currently disabled the Apple Pay button on third party websites because the broken button didn't look good. https://www.evite.com/event/0156KN4OYQ376UYDQEPORPISJ63XPI/donate?gid=01C874OLTSHFCE73EEPOTNYI2PK57Y&emhm5=9e1d67d654d86ffc99b4f5ceba5af504&emhs1=30ec1a3bc0c43e5700a1b4b541ef6f6d8a30b808&emhs2=fdfc2f6beb29a601fe8ae0d429d4867e0bfee3f959d6019da06b2b1a54395aa8&utm_campaign=donate_now_bt&utm_content=&utm_medium=email&utm_source=CHARITY_DONATION

#

There are hundreds of examples of other websites embedding our widget where they don't have a Stripe account, and the Apple Pay button appeared but never worked. Legacy.com is such a partner. They've had many impressions of the Apple Pay button on their obituaries but no donations, meaning it's not working there.

#

One curious example that stands out though is a website built on one of those drag and drop platforms that isolate any custom code you try to embed. It wrapped our embed script in an iframe that lacked the allow="payment" attribute. This resulted in Apple Pay throwing an error and the initialization of the form hanging, instead of the promise resolving with a null value like it did for Google Pay in Chrome. This has to be a bug in Stripe JS as I imagine the desired behavior would be the same as a failure to initialize Google Pay which does resolve canMakePayment with a null value. This is the website in question. Our check to disable cross domain Apple Pay avoided the error so it now loads. https://www.worthyoflovela.org/donate

#

This is basically how we disable cross domain Apple Pay for now

const sameOrigin = (() => {
  try {
    return location.origin && location.origin == top.location.origin
  } catch (e) {
    return false
  }
})()

const disableApplePay = !sameOrigin && typeof ApplePaySession != 'undefined'```
#

To give you a live example where things aren't working, we'd have to remove the above check, but isolate it so that only you can see it since it's not a good look to have a broken Apple Pay button everywhere our forms are being used.

warm heathBOT
marsh torrent
#

Ok, let me read all that and poke at some things

marsh torrent
#

You'd need to register the domain for your platform, in any case

orchid stump
marsh torrent
#

Ok, sure. So you collect them to your platform.

#

And there's no connected account involved, just an iframe Elements integration for your account

orchid stump
#

The issue isn't getting the money to them, but that the Apple Pay button has appeared on the forms when embedded on their websites, but it doesn't work, except intermittently for a partner (Evite; not a nonprofit) who happens to be a Stripe customer, but we don't collect money for their Stripe account. It's just a curious thing that Apple Pay seems to work there intermittently.

marsh torrent
#

It does require allow=payment and the parter domain needs to be registered with your stripe account in that case

#

We're wokring on fixing that -- right now, the logic to decide to show the button is based on the frame domain and Apple requires the top-level parent domain to be registered to collect payment

#

THat's why you currently need both

orchid stump
#

OK, so we just need to add Evite.com to our list and it should work, right? For other partners, we'd want to add their domain and ask them to upload the .well-known file to their website as well, right?

marsh torrent
#

Correct

orchid stump
#

Sweet. Thank you! We'll try that

marsh torrent
#

Just be aware that if/when you do end up using direct charges on connected accounts, that domain registration needs to be done with the same pattern as the payment

#

ie, if you're doing a payment intent via connect using the stripe-account header, you init Stripe.js using that same account and the stripeAccount option, and the relevant domain(s) must be registered on the connected account using the connect header also