#Aleksey-pmd-apple-pay
1 messages · Page 1 of 1 (latest)
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
In that case, is it OK to add a domain for a partner to our account when they also have their own Stripe account?
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?
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
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
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
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
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)
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?
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
Can you share a specific connected account ID I can look at for the domain registration?
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
Is there a public site I can visit to see this working / not working more concretely?
Here's a page for one of the nonprofits we support https://www.pledge.to/organizations/46-4664562/one-tree-planted-inc
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.
Ok, let me read all that and poke at some things
other websites embedding our widget where they don't have a Stripe account
So, for these cases, you're collecting payment to your platform account? How do they get the funds without an account?
You'd need to register the domain for your platform, in any case
Some of our partners aren't nonprofits and they embed our form in order to help raise money for the nonprofits, not for themselves. The nonprofit partners that are raising money for themselves also don't get the funds immediately, but rather our foundation receives the donations and then regrants them to the appropriate nonprofits later, whether via check, ACH, or other payment methods.
Ok, sure. So you collect them to your platform.
And there's no connected account involved, just an iframe Elements integration for your account
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.
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
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?
Correct
Sweet. Thank you! We'll try that
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