3

I'm working on integrating PayPal Express Checkout into an existing web application for which I've already setup Google Checkout and Amazon Payments (both SimplePay and CBA). So I'm not new to this.

Everything, including the Instant Update Callback, works fine in a setup that uses Sandbox settings. The Callback works fine both on HTTP and HTTPS in the Sandbox. But as soon as I switch to Live credentials, the PayPal UI stops hitting the CallbackURL and falls back to using the (fall back) shipping costs sent in SetExpressCheckout. Obviously, taxes aren't calculated at all.

I'm using the latest version of the PayPal PHP SDK (version 106.0). The only settings that are changed to switch the setup from Sandbox to Live are:

  • UserName
  • Password
  • Signature
  • mode (from sandbox to live)

I see a similar issue posted on PayPal's Community Help Forum, but it doesn't mention a solution. For some reason I can't seem to post in that thread ... perhaps because it's archived.

Update 9/16/2013: Seems to be an HTTPS related issue. Sandbox doesn't work on HTTPS either, but there's no SSL error when hitting callback URL from browser. Certificate is valid and perfectly acceptable to other payment vendors that we use on the site: Google Wallet and Amazon Payments.

Philipp
  • 60,671
  • 9
  • 107
  • 141
Jaffer
  • 745
  • 1
  • 9
  • 20
  • Contact PayPal support? – Halcyon Aug 30 '13 at 09:36
  • Contacted them a couple of days ago, haven't heard back yet (probably due to long weekend). – Jaffer Sep 02 '13 at 13:02
  • Hey Jaffer! Sorry to hear about these pains.. this was actually the most troubling thing I came across when doing a lot of work with the PayPal API. You may be hitting the same thing I was hitting: There is a sneaky little bug that causes odd results in production when setting a callback timeout of anything *except* 3. The callback timeout is basically a useless parameter, and I spent a month proving to the developers that it was, with them implementing a "fix" and then ignoring me when I proved that also did not work. – SgtPooki Sep 11 '13 at 14:55
  • If you can update your answer with your actual Express Checkout request, I may be able to provide some assistance. Also, please note that paypal-community.com is really only used by the PayPal community (see 'not really used by PayPal'). If you want help, *quickly*, from PayPal, for API issues, call PayPal tech support, or open a ticket with them: https://ppmts.custhelp.com/ – SgtPooki Sep 11 '13 at 14:58
  • 1
    @SgtPooki, I've gotten in touch with a PayPal tech support rep via www.paypal.com/mts. I'll update this question with a solution when we find it. Seems to be an HTTPS related issue. – Jaffer Sep 16 '13 at 11:41
  • 1
    @SgtPooki Thanks for mentioning the timeout value, but I'm already using a value of 3. :( – Jaffer Sep 16 '13 at 11:41
  • 1. Is your callback script on an HTTPS server? 1. Is the SSL certificate on your HTTPS server signed by a "mainstream" CA? (PayPal won't connect to your site if the SSL certificate is self-signed or signed by an unrecognized CA.) – Matt Cole Aug 30 '13 at 12:19
  • Yes, callback is on HTTPS, works fine when using sandbox settings. No security warnings when accessing URL via a browser. Cert is issued by GoDaddy and is valid for another couple of years. – Jaffer Sep 02 '13 at 06:11
  • Can you post the correlation ID from your SetExpressCheckout call? – Matt Cole Sep 10 '13 at 21:39
  • @MattCole, just realized you work at PayPal. I was focusing on coordinating with a rep in PayPal's Tech Support website. FYI, I've been told that my ticket has been escalated to the dev team. The reference # for my ticket is 130830-000045. I just triggered a SetExpressCheckout from a Live configuration. The Token ID is EC-9HD00258GX2814844 (that's what you mean by correlation ID right?). Hoping you can help me out. – Jaffer Sep 24 '13 at 04:33
  • @Jaffer did they ever give you a satisfactory response? – Simon_Weaver Mar 05 '14 at 08:33
  • @MattCole is Godaddy not considered mainstream? my godaddy EV certificate doesn't even work. why does this restriction even apply. you're retrieving shipping information, not bitcoins – Simon_Weaver Mar 05 '14 at 20:26

3 Answers3

2

This issue was fixed by: 1. Setting CallbackTimeout to 6 2. Using an SSL certificate that is accepted by PayPal. In our case, the cert was issued by "Go Daddy Root Secure Certificate - G2", which wasn't accepted by PayPal's system.

Jaffer
  • 745
  • 1
  • 9
  • 20
  • which company did you have to switch to? – Simon_Weaver Mar 25 '14 at 19:42
  • I meant which SSL company :-) – Simon_Weaver Jun 08 '15 at 21:00
  • I had the same issue early in 2014. Paypal technical support eventually told me that their system was not setup to accept SSL certificates with SHA-2 signatures (05/26/2014). We setup another server who's only purpose was to forward IPN callbacks to our main website, so we didn't have to downgrade from a SHA-2 signed certificate. They said "as a matter of fact, your request triggered a process to upgrade our certificate." whatever that means, and said it would take 3-6 months. Haven't tested it with SHA-2 since. – Marcus10110 Jul 22 '15 at 00:23
0

I had this problem with a Godaddy UCC certificate, but did not have the problem with a non UCC certificate. So I had to write a proxy to redirect the request to the correct location.

However recently this too has failed with my Godaddy certificate so they seem to be being less permissive rather than more permissive. It even fails with an EV certificate.

It makes no fricking sense. All the callback URL does is provides shipping rates! How secure does that need process need to be. It's ridiculous! No solution right now other than changing certificate which I can't even guarantee will work.

Simon_Weaver
  • 120,240
  • 73
  • 577
  • 618
  • The callback request contains PII (Personally Identifiable Information i.e. the customer's location). Therefore, privacy laws in most countries will require it to be protected. – Jim OHalloran Jul 13 '16 at 07:53
  • Yes but ANY SSL should be sufficient for this. I am not trying to use it without an certificate. If there is any specific requirement for SSL then PayPal needs to make it clear what that requirement is. Right now they just seem to reject certain companies certificates for no reason (last time I checked). – Simon_Weaver Jul 13 '16 at 07:55
0

I managed to get it working with a FREE certificate from startcom.org (heard about on Security Now Podcast).

Their website is horrible, but PayPal seems to be OK with their certificate where they aren't OK with a Godaddy certificate - both 4096 bits. Plus it's free :-) Although only good for a year.

As soon as I switched to this certificate it worked fine.

It was definitely something unacceptable to PayPal about the GoDadaddy/Starfield issued certificate.

There is also a service ngrok which I found very useful to allow me to test locally. It allows you to set up a tunneling proxy that is accessible from the outside. Even without touching firewall settings you can create an address like http://83def5f1.ngrok.io that is accessible by PayPal and redirects traffic to your local machine allowing you to set breakpoints.


Proxy page

(Completely unrelated to ngrok)

I preferred not to use this certificate for my live sites (plus I have several different sites on UCC certificates I didn't want to change), so I made a proxy page that redirects the request to the right server. I then just send the following to PayPal

"https://example.com/paypalproxy.aspx?callbackUrl=" + HttpUtility.UrlEncode(callbackUrl)

(Where callbackUrl is your regular callback URL that you would send to PayPal)

The proxy is an ASPX page - it doesn't need to be compiled just put into a .NET IIS website.

You can check to see the last request/response calling it with ?debug=Y

<%@ Page language="c#" AutoEventWireup="true" %>
<%@ Import Namespace="System.IO"%>
<Script runat="server" language="C#">

private static string _lastURL;
private static string _lastRequest = "";
private static string _lastResponse = "";
private static DateTime? _lastTime;
private static int _lastDurationMs;

    private void Page_Load(object sender, System.EventArgs e)
    {
        // no cache
        Response.Cache.SetCacheability(HttpCacheability.NoCache);

            var sw = new System.Diagnostics.Stopwatch();
            var wc = new System.Net.WebClient();
            sw.Start();

            var callbackUrl = Request.Params["callbackUrl"];
            var debugMode = Request.Params["debug"] == "Y";

            if (debugMode) 
            {
               Response.ContentType = "text/text";
               Response.Write(_lastTime + "\n");
               Response.Write("LastURL = ["+_lastURL+"]\n\n");
               Response.Write("LastDuration = [" + _lastDurationMs +"]\n\n");
               Response.Write("REQUEST: \n[\n  "+_lastRequest.Replace("&", "&\n  ")+"\n]\n\n");
               Response.Write("RESPONSE: \n[\n  "+_lastResponse.Replace("&", "&\n  ")+"\n]");
               Response.End();
           return;
            }

            _lastDurationMs = -1;
        _lastURL = Request.Params["callbackUrl"];
            _lastTime = DateTime.Now;

            if (callbackUrl.Contains("dev."))
            {
                throw new ApplicationException("Callback shouldn't be to a dev machine!");
            }
                        
            if (callbackUrl.Contains("https") == false)
            {
                throw new ApplicationException("Callback must be https");
            }
            
            var newUri = callbackUrl + "?" + Request.Form.ToString();

            var str = wc.DownloadString(newUri);

            _lastRequest = Request.Form.ToString();
            _lastResponse = str;
            _lastDurationMs = (int)sw.ElapsedMilliseconds;

            Response.Write(str);
            Response.End();

    }

</Script>
Community
  • 1
  • 1
Simon_Weaver
  • 120,240
  • 73
  • 577
  • 618