Adaptive Payments with PayPal

When building B2C systems the common scenario is to share the profits among the portal and the business users eg. when renting a house through you website the user pays total amount for the house, lets say 100 USD to the property owner. From that amount the owner will pay share commission to the portal’s website usually a small %.

In order to automate this process we can use PayPal Adaptive payments (chained transaction). The main difference between PayPal chain transaction and parallel transaction is that with the chained transaction the user sees only the total amount that he owns to the house owner. With the parallel transactions the user pays total amount but he sees the list of 2 receivers; the house owner and the portal owner share details.

Although there is a good documentation available on the Paypal website I found it very hard to get a working example of the payment implementation. That’s why I decided to post it here.

Lets start with downloading PayPal SDK. It contains all classes we need to make payment request. I have also included project and SDK at the bottom of this article.

When making a payment request we basically need to create paykey and redirect user to the payment page by passing that key as a parameter.
This simply creates initial payment record on PayPal account. The payment then may be finished or cancelled by the user. We get the paykey after getting response from PayPal with the status “CREATED”.

  if (ap.isSuccess.ToUpper() != "FAILURE")
  {
      if (PResponse.paymentExecStatus == "CREATED")
      {
          return PResponse.payKey;
      }
   }

In the init request we need to include basic parameters such as portal and property owner PayPal accounts, api credentials (sandbox account for testing)

    var OrderID = Guid.NewGuid().ToString();

    var portalPayPalEmail = ConfigurationManager.AppSettings["PORTAL_PAYPAL_EMAIL"];
    payRequest.ipnNotificationUrl = ConfigurationManager.AppSettings["PAYPAL_NOTIFICATION_URL"] + "?custom=" + OrderID; // to be processed later in PayPal-Call-back.ashx handler

    payRequest.cancelUrl = Request.Url.ToString();
    payRequest.returnUrl = Request.Url.ToString();
    payRequest.memo = OrderID;
    payRequest.trackingId = OrderID;

    payRequest.clientDetails = new ClientDetailsType();
    payRequest.clientDetails = ClientInfoUtil.getMyAppDetails();  //helper - gets values from web.config
    payRequest.actionType = "PAY"; // or CREATE
    payRequest.currencyCode = "USD";//set currency to user settings
    payRequest.requestEnvelope = new RequestEnvelope();
    payRequest.requestEnvelope = ClientInfoUtil.getMyAppRequestEnvelope(); //helper - gets values from web.config

This is how the config file should look like (please fill in with your data)

 <appSettings>
    <!-- PayPal configuration settings START-->
    <add key="deviceId" value="testID123"/>
    <add key="ipAddress" value="127.0.0.1"/>
    <add key="TrustAll" value="true"/>
    <add key="ENDPOINT" value="https://svcs.sandbox.paypal.com/"/>
    <add key="PAYPAL_URL" value="https://www.sandbox.paypal.com/"/>
    <add key="PAYPAL_REDIRECT_URL" value="https://www.sandbox.paypal.com/webscr?cmd=_ap-payment&amp;paykey="/>
    <add key="PAYPAL_NOTIFICATION_URL" value="https://your-website-url/PayPal-Call-back.ashx"/>
    <add key="APPLICATION-ID" value="APP-80W284485P5195333"/>
    <add key="API_REQUESTFORMAT" value="SOAP11"/>
    <add key="API_RESPONSEFORMAT" value="SOAP11"/>
    <add key="API_AUTHENTICATION_MODE" value="3TOKEN"/>
    <add key="PORTAL_PAYPAL_EMAIL" value="portal-paypal-email"/>
    <add key="API_USERNAME" value="api-username"/>
    <add key="API_PASSWORD" value="api-password"/>
    <add key="API_SIGNATURE" value="api-signature eg.AFcWxV21C7fd0v3bYYYRCpSSRl31AI0QDNGia62b0stzcLxkJCYRE9JE"/>
    <!-- PayPal configuration settings END-->
  </appSettings>

Next we need to define who will pay the PayPal commission, it can be one of the receivers or sender or all can be paying equally

 payRequest.feesPayer = "EACHRECEIVER"; //SENDER,PRIMARYRECEIVER,SECONDARYONLY

Next step is to create receiver list. It can include up to 6 accounts. In our case we have only portal user and the property owner. The total amount of 100 USD will be split to 80 USD for the property owner and 20 USD for portal (minus PayPal commission taken from both receivers)

    payRequest.receiverList = new Receiver[2];
    //pay the user
    payRequest.receiverList[0] = new Receiver();
    payRequest.receiverList[0].amount = 100;
    payRequest.receiverList[0].primary = IsChainedTransaction;// set to true to switch to chained transaction
    payRequest.receiverList[0].primarySpecified = IsChainedTransaction;// set to true to switch to chained transaction
    payRequest.receiverList[0].paymentType = "SERVICE";
    payRequest.receiverList[0].email = "portal-user-paypal-email";//set user paypal email

    //pay portal share
    payRequest.receiverList[1] = new Receiver();
    payRequest.receiverList[1].amount = 20;
    payRequest.receiverList[1].primary = false;
    payRequest.receiverList[1].primarySpecified = false;
    payRequest.receiverList[1].paymentType = "SERVICE";
    payRequest.receiverList[1].email = portalPayPalEmail;

At the end we need to supply credentials and send payment request.

 AdapativePayments ap = new AdapativePayments();
 ap.APIProfile = ClientInfoUtil.CreateProfile(); //helper - gets values from web.config

 PayResponse PResponse = ap.pay(payRequest);

The last step is to check if payment was successful and process the order in our application. In the web.config we defined PAYPAL_NOTIFICATION_URL as handler page PayPal-Call-back.ashx. So in the handler when we receive an callback we simply validate it by sending back request to PayPal. When the request is validated we can proceed with our order.

 public void ProcessRequest(HttpContext context)
 {
    Request = context.Request;

	//Request["custom"] contains our orderID
    if (IsRequestFromPaypal() && Request["custom"] != null)
    {
        var orderID = Request["custom"];
            
        //check the payment_status is Completed
        //check that orderID has not been previously processed
        //check that receiver_email is your Primary PayPal email
        //check that payment_amount/payment_currency are correct
        //process payment
    }
  }

   //validate request by sending it back to PayPal
   bool IsRequestFromPaypal()
   {
        var validationRequestContent = Request.Form + "&cmd=_notify-validate";
        var validationUrl = System.Configuration.ConfigurationManager.AppSettings["PAYPAL_URL"].TrimEnd('/') + "/cgi-bin/webscr";

        // Create a Web Request:
        var validationRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(validationUrl);
        validationRequest.ContentLength = validationRequestContent.Length;
        validationRequest.ContentType = "application/x-www-form-urlencoded";
        validationRequest.Method = "POST";

        using (var writer = new StreamWriter(validationRequest.GetRequestStream(), System.Text.Encoding.ASCII))
        {
            writer.Write(validationRequestContent);
        }

        // Now send the request and get the response:
        using (var response = validationRequest.GetResponse())
        {
            using (var reader = new StreamReader(response.GetResponseStream()))
            {
                var paypalResponse = reader.ReadToEnd();
                return paypalResponse == "VERIFIED";
            }
        }
    }

I have included working example below so you can use it in your testing. Just fill it in with your data. You also need to be logged in to your sandbox account when testing it.
AdaptivePayments

1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading...Loading...