Generic "Sorry — your last action could not be completed" Failure - paypal

I've just switched from using normal "plain text" PayPal buttons to encrypted buttons (both home-made as they need to be dynamic). The plain ones worked fine but I'm running into issues with the Encrypted version. Paypal simply fails with the generic "Sorry — your last action could not be completed" message and provides no further information.
The information I'm posting is...
cert_id=<certificateID>
business=<merchantID>
return=<returnURL>
cancel_return=<returnURL>
notify_url=<ipnURL>
cn=Email Address Needed
lc=GB
currency_code=GBP
button_subtype=services
no_note=0
no_shipping=1
rm=1
charset=utf-8
item_name=<productName>
item_number=<productID>
amount=<value>
Everything in <> is removed for security reasons at this point, but that should give you some idea of what is being encrypted then posted.
The form is simple and is submitted by a jQuery AJAX call (to cut down on the -massive- amount of data that the encrypted buttons add to the page)...
<form id='igp-<prodID>' action='https://www.paypal.com/cgi-bin/webscr' method='post'>
<input type='hidden' name='cmd' value='_s-xclick' />
<input type='hidden' name='encrypted' value='{$paypalData}' />
</form>
PayPal's documentation is rather randomly spread about in terms of what you need to do here, but I can't see anything I'm missing.
If I replace a letter in the cert_id then it still fails with the same message (rather than telling me it couldn't decrypt the data) which gives the impression it's not even getting that far.
Any ideas?
EDIT / Update:
It appears the failure is actually "We were unable to decrypt the certificate id." (shows up when using the Sandbox). The code sent to OpenSSL looks sane (correct '=' matched values).
The code for OpenSSL that I'm using is...
$opensslOutput = trim(shell_exec("export RANDFILE='system/.rnd'; (openssl smime -sign -signer {$keystoreCert} -inkey {$keystoreKey} -outform der -nodetach -binary <<_EOF_\n{$paypalData}\n_EOF_\n) | openssl smime -encrypt -des3 -outform pem -binary {$paypalCert}"));
Which in turn produces a large PCK7Z block and no errors from OpenSSL. So this begs the question, what may Paypal be failing on here? Does the above code no-longer produce a signed block that Paypal likes?

As a workaround and for a superior integration, I would recommend using the Express Checkout API instead.
It can do everything standard PayPal buttons can do and more, and works will all PayPal accounts that can accept money with standard buttons.
Have you tried Express Checkout?
https://developer.paypal.com/docs/classic/express-checkout/integration-guide/ECGettingStarted/
https://devtools-paypal.com/guide/expresscheckout/php?interactive=OFF&env=sandbox
https://devtools-paypal.com/integrationwizard/ecpaypal/main.php
The main difference to note is that, by default, EC requires buyers to sign in or create a PayPal account as they are checking out. You can enable the exact same guest checkout functionality as standard by adding SOLUTIONTYPE=Sole to your initial SetExpressCheckout API call.
Another difference to note is that with EC, the customer will always return to your site before the payment is completed. This is a good thing, as you will have the opportunity to either present the customer with an order review page and update any totals, or simply execute the payment immediately, get an immediate API response, and immediately thank or ask the customer to try again.
Basically, EC is better in every single respect. You just need to be able to write HTTPS API calls from your server to PayPal.

Related

What is the PayPal PDT URL to retrieve transaction details?

I'm setting up Payment Data Transfer (PDT) in PayPal.
After a purchase PayPal redirects the user to my return page and I have the tx parameter from the URL.
I also have my unique PDT token from the PayPal profile settings page.
The documentation says the next step (step 3 in the diagram) is:
Your return URL web page contains an HTML POST form that retrieves the transaction ID and sends the transaction ID and your unique PDT token to PayPal.
That's fine.
But what is the PayPal URL that I POST this data to, to retrieve the transaction details? And what form / parameter names do I use?
I've read multiple pages on the PayPal documentation site but can't find any reference to this PDT URL!?
When you enable PDT via your PayPal dashboard, PayPal sends you a confirmation email. In this email is a link to, what appears to be, hidden documentation!
https://developer.paypal.com/docs/classic/paypal-payments-standard/integration-guide/paymentdatatransfer/
Post a FORM to PayPal that includes the transaction ID and your identity token, a string value that identifies your account to PayPal. The form looks like this:
<form method=post action="https://www.paypal.com/cgi-bin/webscr">
<input type="hidden" name="cmd" value="_notify-synch">
<input type="hidden" name="tx" value="TransactionID">
<input type="hidden" name="at" value="YourIdentityToken">
<input type="submit" value="PDT">
</form>
In PayPal's reply to your post, the first line is SUCCESS or FAIL. A successful response looks like this, with the HTTP header omitted:
SUCCESS
first_name=Jane+Doe
last_name=Smith
payment_status=Completed
payer_email=janedoesmith%40hotmail.com
payment_gross=3.99
mc_currency=USD
custom=For+the+purchase+of+the+rare+book+Green+Eggs+%26+Ham
...
I initially discarded this email without reading it, which is why I missed the secret documentation!
I also found this stackexchange question which references a much older PayPal documentation page which says the same thing:
https://www.paypal.com/us/cgi-bin/webscr?cmd=p/xcl/rec/pdt-techview-outside
But again, the documentation page is not browsable, so you must happen to know the exact URL to find it!

Verify cancel_return parameters

When I click the cancel link in PayPal and am redirected to my cancel_url, it is passed the following parameters (some values removed).
cmd=_flow&
myAllTextSubmitID=&
miniPager=&
currentSession=&
pageState=login&
currentDispatch=&
email_recovery=false&
password_recovery=false&
login_email=&
login_password=&
private_device_checkbox_flag=on&
SESSION=&
CONTEXT=&
cmd=_flow&
id=&
close_external_flow=false&
external_close_account_payment_flow=payment_flow&
cancel_return=&
auth=&
form_charset=UTF-8&
external_remember_me_read_cookie_ids=&
flow_name=xpt%2FCheckout%2Fwps%2FLogin&
fso=
Is there any way to verify that this is a legitimate cancelation similar to how IPN verify works?
None of this looks like PayPal data. It looks like you're passing that stuff to yourself in the cancel URL, or via your original form. In which case you can pass yourself a ticket that only you can generate and verify. There's no need from Paypal's point of view to provide a verification, as no transaction has occurred.

Display users's email after purchase with Paypal Website Payments Standard

I have a simple button created with Paypal's Website Payments Standard, and I'm using the feature "Take customers to this URL when they finish checkout".
On that page which users are being redirected to when the purchase is successful (on my site) I'd like to simply display the email associated with their paypal purchase, telling them something like "an invoice will be sent to this email address: xxx".
Is that possible without using the API or IPN (which I'd rather avoid because it seems like I can't set different IPN urls for deifferent buttons/products.)
Ended up using PDT, there's a great example of how to simply do this here:
http://www.geekality.net/2010/10/19/php-tutorial-paypal-payment-data-transfers-pdt/
Thanks PP_MTS_Chad, I wouldn't have found it if it wasn't for you pointing out that option.
You could use 1 of 2 ways to get information back to your return URL, without having to use IPN or an API. You could use PDT to return information back to your site, or you could use the return method which uses the variable "rm". You can find more out about IPN here, and there are also some sample scripts you can use on that site as well.
If you want to use the return method, this is a little different from PDT. With the return method you do not have to post the information back to PayPal to verify it. If you wanted PayPal to post the information over to your return page you would just simply enable auto return in your account under your profile. Then you would just include the following lines of code in your button code.
<input type="hidden" name="rm" value="2">
<input type="hidden" name="return" value="http://www.mysite.com/return.php">
The variable "rm", controls how you want the information sent back to you. You can set it to be a GET or a POST.
Allowable values are:
0 – all shopping cart payments use the GET method
1 – the buyer's browser is redirected to the return URL by using the GET method, but no payment variables are included
2 – the buyer's browser is redirected to the return URL by using the POST method, and all payment variables are included
The default is 0.
Note: The rm variable takes effect only if the return variable is set.

paypal redirect on successful checkout

I am trying to get my Paypal subscription to redirect to a custom page after a successful checkout.
Before submitting to Paypal I overload the submit handler, run my own function (to store details) and return a unique id. I want to attach that id to my return URL. (as a GET or POST var so to speak)
I have turned auto redirect "on" in my Paypal sandbox sellers preferences, but it only seems to re-direct to the URL that I HAVE to put in there.
using the <input type="hidden" name="return" value="someurl" /> does no seem to work.
I want it this way so that I can capture the user information when entered with a "non-paid" flag, then via the IPN I can update that record with a "PAID" flag, and I want to use the unique ID to tie it all together so to speak.
Your hidden field name needs to comply with the accepted variable name required by PayPal. Does ReturnUrl (not case-sensitive) not work?
<input type=hidden name="RETURNURL" value="https://www.YourReturnURL.com">
Note: I have only investigated and implemented express checkout so this may not apply to your implemenation: https://cms.paypal.com/en/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECGettingStarted

Can I send a variable to paypal, and have it post it back to me when payment completes?

Ive been using express checkout API to convert people's accounts on my site to premium accounts after paying. The only problem with it is that it doesn't send the user back to the site until they click the button to return, and it updates their permission when that happens. About 40% of the users don't seem to do that.... so their accounts never get credited after payment.
Although paypal does an instant post-back upon the successful payment, I was never able to make it actually update the user's account right away, since I cant get it to send back some sort of informational that would identify the user that just completed the payment. I could only do that when you are sent back to the site, which sends the transaction ID, that I logged with a post-back. It searches for it, and grants permission if it was found int he DB.
Is there a way to submit some sort of a variable to paypal, that it will then post back to me? Something like &user_id=123, which would make it very handly to update the user's permission.
Iten_number hidden variable don't work in my application. But i found that custom hidden field works fine. Just add this field to the form, generated by paypal: <input type="hidden" name="custom" value="YOUR VALUE FROM DB"/>. After, you can read this value to identify, for example, what product have been purchased. (Java code): String custom = request.getParameter("custom");
Yes, if you send item_number, the IPN notification will include that when it posts back to you. I record a unique ID in the database when the user starts the payment process, and include that when sending them to PayPal. When the IPN comes in, that unique ID matches up with the record in the database, giving me all the info I need.
Edit Re your comment:
I expect there's a code example somewhere on the site linked above, but basically in my case I'm using a form that I POST to https://www.paypal.com/cgi-bin/webscr. Within that form are various hidden fields documented in the IPN stuff (cmd for what command to perform, business to specify your business ID, item_name for a nice description in the PayPal UI, item_number for the item number I mentioned above, etc., etc.). When IPN posts back to your IPN address, it includes various fields (such as payment_status — kind of important! &mdash and the item_number you fed in when posting to them).
Just to add to this old question...
There are option parameters that are commonly used for custom data sending through paypal.
These option tags are on0, on1, or on2 for the custom field names and os0, os1, and os2 for the custom field values.
I would send on0 with a value of "UserID" and os0 the actual ID.
These values will be represented in the IPN as follows:
os0 is represented as option_selection1
os1 is represented as option_selection2
os2 is represented as option_selection3
on0 is represented as option_name1
on1 is represented as option_name2
on2 is represented as option_name3
Here's the info on PayPal's HTML parameters
According to HTML Variables for PayPal Payments Standard you can send all the "Pass-through" variables:
item_number Pass-through variable for you to track product or service
purchased or the contribution made. The value you specify is passed
back to you upon payment completion. This variable is required if you
want PayPal to track inventory or track profit and loss for the item
the button sells.
custom Pass-through variable for your own tracking purposes, which buyers do not see. Default – No variable is passed back to you.
and
invoice Pass-through variable you can use to identify your invoice number for this purchase. Default – No variable is passed back to
you.
All these pass-through variables are sent back by the IPN in the payment response info.
You just have to render your HTML template server-side and write the fields back in the HTML code like
<input type="hidden" name="item_number" value="{{ productID }}">
<input type="hidden" name="invoice_id" value="{{ invoiceID }}">
<input type="hidden" name="custom" value="{{ jsonInfo }}">
Technically the field "custom" can be a JSON encoded string if you want to handle more data like
myItemObject = {
"customerEmail" : "john#doe.com
"customerID: "AAFF324"
}
jsonInfo = json.dumps( myItemObject )
return render_template(tmpl_name, jsonInfo=jsonInfo, productID=productID, invoiceID=invoiceID)
I finally get this answer, I want to share with all of you look:
on your HTML form put this code (this is Paypal sandbox):
form action="https://www.sandbox.paypal.com/cgi-bin/webscr?custom=YOUR_VAR" method="post"
On your PHP after the Paypal redirect to your page success: use the cm GET variable:
$example = $_GET["cm"];
I hope this URL solves your issue. As it solved mine as well. Add a custom variable to your form and then retrieve it on your success payment page.
Example :
<input type='hidden' name='custom' value='<?php echo $email; ?>'/>
and then retrieve it as :
$_POST['custom']
<input type="hidden" name="on0" value="Ajay Gadhavana">
<input type="hidden" name="on1" value="my_phone_number">
<input type="hidden" name="on2" value="my_third_extra_field">
Response from paypal would be
[option_name1] => Ajay Gadhavana
[option_name1] => my_phone_number
[option_name1] => my_third_extra_field
What worked for me in 2021 is passing "custom_id" (inside the "purchase_units" array) to PayPal in my client app and checking "custom" on my backend.
Yes, it looks like PayPal renames the parameter for some reason.