400 Bad Request when button pressed - happening more frequently!

FixItDik
Contributor
Contributor

Hi,

Background: I needed a quick way to take fixed amount one-off payments from my "customers" (motorcycle owners club members) so thought the PayPal Checkout buttons looked to be perfect. Developed on sandbox and put live in a hurry but was working pretty much fine at first.

What's reported by users: But after a couple months I am seeing increasing numbers of people attempting to pay using the buttons (both PayPal and Card) who are trying over and over. Luckily I store their email addresses in the "Orders" table I create for each attempt so I reached out to them and they tell me they are just seeing the rotating circle if they click the card button or nothing if they click the PayPal button.

What I found: So I went to the live web site and tried myself using their details and sure enough I see exactly the same. I opened Developer Tools in Chrome and I am seeing the following appear in the console when I click the button:

 

GET https://www.paypal.com/smart/card-fields?sessionID=2ac27243e1_mte6mtm6mdy&buttonSessionID=64587ec80e... 400

 

The hardest thing for me here is that it is working for some people and not for others, but as the title suggests is started out with 1 in 20 people now it is line 4 in 5 (i.e. only one attempt in every 5 is successful)

 

Because it sometimes works and because it has been getting worse this feels like a compatibility issue somewhere but the people I have contacted have told me they are trying different devices with different browsers.

 

Here's an extract of my page:

 

 

 

 

 

 

<html>
<head>
  <!-- my stuff -->
  <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Ensures optimal rendering on mobile devices. -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- Optimal Internet Explorer compatibility -->
</head>
<body>
  <script
    src="https://www.paypal.com/sdk/js?client-id={MY_CLIENTID}&currency=GBP" data-order-id="{My Order ID}">
  </script>
  <!-- my stuff -->
  <!-- my 'please wait' message that is shown when PayPal confirms authorisation -->
  <div id="PleaseWait" style="display:none;position: fixed;top: 50%;left: 50%;width: 300px;line-height: 200px;height: 200px;margin-left: -150px;margin-top: -100px;background-color: #f1c40f;text-align: center;z-index: 10;font-size:40px;outline: 9999px solid rgba(0,0,0,0.5);">Please Wait</div>

  <div id="paypal-button-container"></div>
  <script>
    ppoid=pptid='';
    paypal.Buttons({
		createOrder: function(data, actions) {
			// This function sets up the details of the transaction, including the amount and line item details.
			return actions.order.create({
       			style: {
       				label: "pay"
       			},
				application_context: { 
				    brand_name: 'Our Club Name',
				    shipping_preference: 'NO_SHIPPING'
				},
				purchase_units: [{
					reference_id: '{My Order ID}',
					amount: {
						value: '{total to pay}',
						currency_code: 'GBP'
					}
				}],
				payer: {
					name: {
						given_name: '{FIRST}',
						surname: '{LAST}'
					},
					email_address: '{EMAIL}',

					address: {
						country_code: '{Country CODE}', 
						address_line_1: '{ADD1}',
						address_line_2: '{ADD2}',
						admin_area_2: '{TOWN}',
						admin_area_1: '{COUNTY}',
						postal_code: '{POSTCODE}'
					}
				}
			}).then(function(details) {
				ppoid = details;
				return details;
			});
		},
		// this function handles the successful outcome
		onApprove: function(data, actions) {
			x = document.getElementById('PleaseWait');
			if (x) {x.style.display='inherit';}
			return actions.order.capture().then(function(details) {
				pptid = details.purchase_units[0].payments.captures[0].id;
				setTimeout(function(){window.location.href='thankyou.php?oid={My Order ID}&ppoid=' + ppoid + '&pptid=' + pptid;}, 500);
				return details;
			});
		},
	    onError: (err) => {
	      console.error('*** error from the onError callback', err);
	    }
	}).render('#paypal-button-container');
    // This function displays Smart Payment Buttons on your web page.
  </script>
</body>

 

 

 

 

 

 

As you can see I have modified the script a little from the examples in the documentation (but used other areas of the docs and questions on this forum to get them right):

  • I have added some elements to the order.create parameter
  • Added the onApprove hook to I can redirect the payer to a Thank You page (showing a Please Wait for the few seconds that takes to avoid them clicking anything else)
  • Added the onError hook which does not get triggered even though the JavaScript console is showing me the above 400 error when the button is clicked

In the background:

  • Before drawing this page my code generates an orderID and stores their info in a database table (the "{My Order ID}" gets populated on this page with that)
  • When drawing this page all the things that look like "{xxx}" get replaced with the transaction information - before you ask no the use of curly braces is not conflicting with the JSON, I can see the code in the developer tool is exactly as it should be
  • I have set up webhooks so that when PayPal authorises and Completes the transaction there is a small bit of code that simply updates the database record - identified by the {My Order ID} which travels with the order - and on completion emails the person (and CCs me) with 
  • By the time the person lands on the Thank You page the PayPal web hook has usually triggered and the person is shown the payment confirmation - obviously no web hooks are triggered as the person is not even getting the chance to pay
  • This leaves me with a database table that is filling up with uncompleted transactions as the people try and try again (I am not worried about space, just about the very poor user experience and the fact we are losing money!)

Please help!

Thanks

 

Dik.

Login to Me Too
1 REPLY 1

FixItDik
Contributor
Contributor

I found the problem: I was initially trying to populate the order data with the person's phone number (from the data in my membership database) but soon realised that was only relevant if they were based in the UK so put the logic for that in with the logic that detected an ISO country code of "UK" and replaces it with the PayPal-required value of "GB". Unfortunately the members type all sorts of rubbish in the phone number field so trying to clean it up to look like a real number (which the PayPal JSON object will only accept) resulted in too many failures so I simply stripped out the logic to populate the "{PP_PHONE}" line in my HTML - *MY STUPID MISTAKE* was to also then remove the logic for the country code so I was sending "UK" instead of "GB".

 

Why oh why did PayPal allow me to create the order with "invalid" data and not throw some form of error at the point of order creation rather than this really bad user experience! Anyway, the real anger is pointed at myself for being so slap-dash in my haste to get this working.

Login to Me Too

Haven't Found your Answer?

It happens. Hit the "Login to Ask the community" button to create a question for the PayPal community.