
paypal.version: 5.0.117Code snippet:
paypal.Buttons({
style: {
layout: 'vertical',
color: 'gold',
shape: 'pill',
label: 'paypal'
},
env: 'sandbox',
client: {
sandbox,
production
},
locale: 'en_GB',
createBillingAgreement: onPaypalCreateBillingAgreement,
onApprove: onPaypalApprovedPayment,
onCancel: onPaymentCancelled,
onError: onPaymentError
}).render('#braintree-paypal-cta');
Where onPaypalCreateBillingAgreement simply does paypalCheckoutInstance.createPayment({ flow: 'vault', enableShippingAddress: false })
+1
Um, so it looks like PayPal decided to release a patch update 2 days ago that changed the default from authorize to capture?!?! https://github.com/paypal/paypal-checkout-components/compare/v4.0.311...v4.0.312
We started seeing a slow decline in PayPal payments that directly correlated to this release. My guess is for anybody lucky enough to not have a failure, they had the script cached.
Hi @thefotios -- can you let me know exactly what you're seeing? Capture was always the default, per https://developer.paypal.com/docs/checkout/reference/customize-sdk/#intent
What are you passing in the script tag, and what are you passing when setting up the transaction?
@bluepnume I'm passing intent=authorize to the SDK, but I'm getting this error in the console:
Uncaught Error: Expected intent from order api call to be authorize, got capture. Please ensure you are passing intent=capture to the sdk
I should mention that we're using braintree-web, but we're explicitly passing authorize there as well.
It's very suspect that this commit landed in the 4.x release right when this started happening - https://github.com/paypal/paypal-checkout-components/commit/bc3dbb7fa9959c65bf930c9baf9f03aed2e110ec
@thefotios -- can you share:
a) An example of the code you're using with braintree-web to set up the transaction
b) An example of one of the tokens Braintree is returning to you?
@bluepnume
[email protected] (this code has been working vebatim for ~2 months)I should note that this is a sandbox account. If you need the client ID or anything else, let me know and we can sync up OOB.
Hi @thefotios -- thank you so much, this was enough to narrow it down. It looks like the api is incorrectly returning this as a capture and not an authorize which is why the validation is failing during validation step in the sdk/button.
For now I'm disabling this validation for this specific case. I apologize for the inconvenience here; I'll raise an internal ticket for that API layer to help track down the root cause of the issue.
Thanks again for helping narrow this one down.
@crookedneighbor -- just tagging you here since I'm not sure where this issue originates.
Can you confirm, when the following is passed to Braintree:
instance.createPayment({
enableShippingAddress: true,
intent: 'authorize',
flow: 'vault',
})
What is the intent that is subsequently passed to the PayPal API? Is it authorize?
@bluepnume Thanks for taking care of this! Do you know when these changes will do live or is ther anything I can test out?
As for the intent being passed, this is what tipped us off that something changed - https://github.com/braintree/braintree-web/blob/master/src/paypal-checkout/paypal-checkout.js#L847-L850. You can trace that back to the createPayment call in the same class
On second look, seems like intent is not being passed to https://api.sandbox.braintreegateway.com/merchants/hh4cpc39zq4rgjcg/client_api/v1/paypal_hermes/setup_billing_agreement --

So I assume capture (or sale) must be being set as the default on the BT server side since nothing is being passed...
@thefotios temporary fix is pushed. Please let me know if you still see the issue.
@bluepnume Just tested against sandbox and it's working for me.
As for braintree-web, we're running a Rails app with distinct front and back ends. In our case, everything about the form submission is client side (except that we get a client ID from our backend). We authorize the transaction afterwards on the backend, but it's not even getting that far. Out of curiosity, which object did you dump there?
@thefotios -- looks like the intent: 'authorize' you're passing to Braintree is having no effect. I recommend:
intent=capture when invoking the paypal sdk.That should guarantee future stability here.
@crookedneighbor please confirm if I'm missing anything here.
@bluepnume I'm pretty sure we actually need to use authorize since we've got a somewhat complicated checkout process (a subscription service). We pass the nonce to our backend that captures the transaction as well as vaults the token and whatnot.
Not to sound glib, but doesn't having the library respect the values we tell it to also guarantee future stability?
When using the billing agreement flow, intent should not be passed at all. In the BT SDK, it will just be ignored. In the PayPal SDK, you must omit the intent query parameter.
@crookedneighbor Ok, it's also entirely possible we're doing the wrong thing here (maybe we should be using something other than createBillingAgreement). We're not using braintree or PayPal recurring/subscription capabilities. We're using the authorized token in our own OOB renewal process.
Definitely recommend working with the Braintree team to figure out the correct integration here. That said -- in the mean time, I still highly recommending switching over to intent=capture in the sdk url and removing intent from the Braintree call.
Hi @thefotios -- can you let me know exactly what you're seeing? Capture was always the default, per https://developer.paypal.com/docs/checkout/reference/customize-sdk/#intent
What are you passing in the script tag, and what are you passing when setting up the transaction?
Not sure the above helps my case. Still seeing the error when the PayPal window is closed quickly before it loads - just to start with :(
To give a bit more background history...
We are passing no intent at all! We use PayPal with a vault flow as such:
https://www.paypal.com/sdk/js?client-id=${clientID}&locale=${locale}&disable-funding=card,credit&vault=true
Using braintree-web @ v3.60.0 and create the payment like:
paypalCheckoutInstance.createPayment({ flow: 'vault', enableShippingAddress: false })
Since we have a subscription model, after the payment is accepted (i.e. calling https://api.sandbox.braintreegateway.com/merchants/4ffdb9nd2z9gsm3d/client_api/v1/paypal_hermes/setup_billing_agreement). We get a response like below to be tokenized and get a nonce in return (similar to what @thefotios mentioned above):

But the final steps of the payment all work as expected :) It's only the PayPal SDK 'errors' that are a slight nuisance in the console. If they could be caught somehow from the onError callback passed to paypal.Buttons({})!
Hi @cusero -- sorry, the discussion got a little sidetracked on an unrelated issue. I'll take a look at the problem you initially reported. Thanks.
Any news on this? We're experiencing the same issue.
same issue here ! as soon as I click the PayPal button - window opens & closes with 422 generic error
This should now be resolved. Please let me know if you still see the issue. Thanks!
Issue resolved, indeed! Thank youuu @bluepnume 馃檶
Still experiencing the issue, right after the div containing the buttons is unmounted.
Yes I was still getting the window closed error in my Vue SPA.
It's not ideal but I got around it by executing the PayPal SDK every time I want to render the button, e.g. append the javascript SDK to the document head and call window.paypal within the script.onload.
Yes, the Issue is still there.

Facing same issue :-(
A boolean is being passed as a fourth parameter to window.open. This is not used and may cause an exception in a future release.
Most helpful comment
Any news on this? We're experiencing the same issue.