This document gives a description for the implementation of the PayPal Express Checkout using the SOAP API. This API is great for asp.net implementations for integrating PayPal into custom shopping carts. I.e, you are a developer who has implemented a custom shopping cart and you now want to implement a payment solution using PayPal.
Why do I not talk about the other PayPal payment solutions. Well, there are plenty of really good web sites out there that does exactly that .
This document is devided into the following sections:
Getting Started with PayPal
Setting up the PayPal API
PayPal Express Checkout
Program Examples using the SOAP API
Updating the Web.Config file
Getting Started with PayPal
First you will need to set up a PayPal test account in the test environment called PayPal Sandbox. You may want to read the Getting Started with PayPal Sandbox documetation before you attempt to do this. Make sure you follow the instructions - first sign up for a sandbox developer account, then create both a personal and a business account (buyer and seller accounts) using the "Create a preconfigured buyer og seller account" link. You will need both for testing. The personal account is used by ýou as the customer, while the business account is used by you as the store owner (merchant).
If you go to http://sandbox.paypal.com without being logged in with your developer account, you will see the following screen instructing you to log in to your developer account.

Setting up the PayPal API
The PayPal API contains a vast number of methods for performing transactions, issue refund, browsing history of transactions, update payment profiles, and so on. See the PayPal API Reference for more information. So how do you start using the API. Well, first you need to enable API access in your account by following these steps:
-
Go to the
PayPal Sandox environment and log in with your developer account
-
Log in to Sandbox using your business account
-
Click the "My Account" tab and then the "Profile" sub tab
-
Click the API Access link under the Account Information header
-
Click the link that says Request API Credentials / View API Certificate
-
Select API Signature or API Certificate
As I find the API Signature easier to set up, I recommend that you use this setting. The discussion in this document assumes this choice.
Now that you have the credentials for making API calls, you are ready to add the Web Service Reference to https://www.paypalobjects.com/wsdl/PayPalSvc.wsdl. After a few moments, you'll have an up-to-date class ready to serve you with all the benefits of strong typing - no building of HTTP requests, no copy-pasting field names, and no cumbersome parsing of responses. You have the same thing available for Sandbox at: https://www.sandbox.paypal.com/wsdl/PayPalSvc.wsdl.
If you don't know how to add Web References, do the following:
-
Right-click on the root item in Solution Explorer
-
Select "Add Web Reference"
-
Enter either the sandbox URL or the production URL in the pop-up window
-
The system will then load the PayPal Web Reference for you - one for the sandbox and one for the production (you should load both). See image below.

PayPal Express Checkout
Express Checkout is the most flexible PayPal integration solution. The user is redirected to PayPal just for authentication and confirmation that he wants to pay for your services, and after that, everything is done on your website; you'll make calls to the PayPal API in the background. The image below illustrates the Express Checkout flow.
-
You'll add a PayPal Checkout button that invokes the
SetExpressCheckout method of the PayPal API after it is clicked.
-
If you are invoking this method for one time payment, it'll be valid if you include only the required fields. Setting the NOSHIPPING variable to 1 is important if you are selling some online service (it'll help you skip the Shipping info page).
-
If you are invoking this method in order to set recurring payments, be sure to set L_BILLINGTYPE0 to RecurringPayments and L_BILLINGAGREEMENTDESCRIPTION0 to a valid description of your service.
-
-
The user will review payment information, and if everything is OK, enter the login credentials. After this, PayPal will redirect him to the URL you specified with RETURNURL when you called SetExpressCheckout.
-
When your
RETURNURL is hit, you need to invoke the
GetExpressCheckoutDetails method and see the details of the actual transaction; verify that everything is in order.
-
Now, all that is left is to commit the transaction. Depending on what you did in step 1, there are two things that can be done.
-
-
For recurring payments, you'll invoke the
CreateRecurringPayments method. It is required that you include the DESC field and match it to the value entered in L_BILLINGAGREEMENTDESCRIPTION0 when you called
SetExpressCheckout.
And this is pretty much it. I will now give code examples showing my implementation of PayPal Express Checkout.
Program Examples using the SOAP API
You need three programs to implement the PayPal Express Checkout SOAP API. First you will need to modify your checkout program. Then you need to write two new programs - one that is called after a successful transaction and one that is called if the user cancelled or the transaction failed.
- Modify checkout.aspx / checkout.aspx.cs (or whatever you called your checkout program)
- Write ExpressCheckoutSuccess.aspx / ExpressCheckoutSuccess.aspx.cs
- Write ExpressCheckoutCancel.aspx / ExpressCheckoutCancel.aspx.cs
First, add the following "using" statements to your checkout.aspx.cs:
using com.paypal.sandbox.www;
//using com.paypalobjects.www; //Production must be commented out when using Sandbox and vice verca.
Then add the PayPal Checkout button in your checkout.aspx program as follows:
<asp:ImageButton ID="ImageButton1" runat="server" OnClick="PostCartToPayPal" ImageUrl="https://www.paypal.com/en_US/i/btn/btn_xpressCheckout.gif" />
The OnClick event "PostCartToPayPal" will call the following method:
protected void PostCartToPayPal(object sender, EventArgs e)
{
//Only process if something in the shopping cart.
if (ctlHandlevogn.MyShoppingCart.Count > 0)
{
// build request
SetExpressCheckoutRequestDetailsType reqDetails =
new SetExpressCheckoutRequestDetailsType();
// Use HttpContext.ApplicationPath to get host address
string url = "http://" +
HttpContext.Current.Request.Url.Authority +
HttpContext.Current.Request.ApplicationPath;
if (!url.EndsWith("/"))
url = url + "/";
reqDetails.ReturnURL = url + "ExpressCheckoutSuccess.aspx";
reqDetails.CancelURL = url + "ExpressCheckoutCancel.aspx";
// 0 - display shipping address
// 1 - do not dispaly shipping address
// 2 - display shipping address from account profile
// if shipping address not provided.
reqDetails.NoShipping = "0";
reqDetails.LocaleCode = "US";
System.Globalization.CultureInfo cultureUS =
System.Globalization.CultureInfo.GetCultureInfo("en-US");
//Calculate shipping cost.
//I will simply set this to USD 100 for this example.
Double sumShipping = 100;
//Save shipping cost in shopping cart as an item in the shopping cart.
//There are other ways to implement shipping cost also, but this works.
ShoppingCartClass.ShoppingItem shoppingCartItem =
new ShoppingCartClass.ShoppingItem();
shoppingCartItem.Antall = 1;
shoppingCartItem.ModellID = -1;
shoppingCartItem.Varenummer =
Convert.ToString(HttpContext.GetGlobalResourceObject(
"Resource", "stringFraktVarenummer"));
shoppingCartItem.Tekst =
Convert.ToString(HttpContext.GetGlobalResourceObject(
"Resource", "stringFraktutgifter"));
shoppingCartItem.Modell_variant_id = -1;
shoppingCartItem.Varenummer_suffix = String.Empty;
shoppingCartItem.Modell_variant_tekst = String.Empty;
shoppingCartItem.Pris = sumShipping;
shoppingCartItem.Fraktpris = 0;
shoppingCartItem.CurrencySymbol = glbCurrencySymbol;
shoppingCartItem.ValutaId = glbValutaId;
ctlHandlevogn.MyShoppingCart.Add(handlevognItem);
reqDetails.PaymentAction = PaymentActionCodeType.Sale;
reqDetails.PaymentActionSpecified = true;
reqDetails.PaymentDetails = new PaymentDetailsType[1];
reqDetails.PaymentDetails[0] = new PaymentDetailsType();
reqDetails.PaymentDetails[0].PaymentDetailsItem =
new PaymentDetailsItemType[ctlHandlevogn.MyShoppingCart.Count];
for (int i = 0; i < ctlHandlevogn.MyShoppingCart.Count; i++)
{
reqDetails.PaymentDetails[0].PaymentDetailsItem[i] =
new PaymentDetailsItemType();
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Amount =
new BasicAmountType();
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Amount.currencyID =
ConvertToPayPalCurrencyCode(
ctlHandlevogn.MyShoppingCart[i].ValutaId);
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Amount.Value =
ConvertCommaToPeriod(
ctlHandlevogn.MyShoppingCart[i].Pris).ToString(cultureUS);
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Name =
ctlHandlevogn.MyShoppingCart[i].Tekst;
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Number =
ctlHandlevogn.MyShoppingCart[i].Varenummer;
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Quantity =
Convert.ToString(ctlHandlevogn.MyShoppingCart[i].Antall);
reqDetails.PaymentDetails[0].PaymentDetailsItem[i].Description =
ctlHandlevogn.MyShoppingCart[i].Modell_variant_tekst;
}
reqDetails.PaymentDetails[0].ShippingTotal =
new BasicAmountType();
reqDetails.PaymentDetails[0].ShippingTotal.currencyID =
ConvertToPayPalCurrencyCode(
ctlHandlevogn.MyShoppingCart[0].ValutaId);
reqDetails.PaymentDetails[0].ShippingTotal.Value =
ConvertCommaToPeriod(sumFrakt).ToString(cultureUS);
reqDetails.PaymentDetails[0].OrderTotal =
new BasicAmountType();
reqDetails.PaymentDetails[0].OrderTotal.currencyID =
ConvertToPayPalCurrencyCode(
ctlHandlevogn.MyShoppingCart[0].ValutaId);
reqDetails.PaymentDetails[0].OrderTotal.Value =
ConvertCommaToPeriod(
ctlHandlevogn.SumPris + sumShipping).ToString(cultureUS);
// Get advertising information and comment field.
// Save in Custom fields for extraction in
// ExpressCheckoutSuccess.aspx.cs.
// Separate items in the Custom field by semicolon.
Int32 adId = Convert.ToInt32(ddlAnnonsering.SelectedValue);
reqDetails.PaymentDetails[0].Custom =
Convert.ToString(adId) + ";" + txtKommentar.Text;
SetExpressCheckoutReq req = new SetExpressCheckoutReq()
{
SetExpressCheckoutRequest = new SetExpressCheckoutRequestType()
{
Version = UtilPayPalAPI.Version,
SetExpressCheckoutRequestDetails = reqDetails
}
};
// query PayPal and get token
SetExpressCheckoutResponseType resp =
UtilPayPalAPI.BuildPayPalWebservice().SetExpressCheckout(req);
HandleError(resp);
// redirect user to PayPal
Response.Redirect(string.Format("{0}?cmd=_express-checkout&token={1}",
ConfigurationManager.AppSettings["PayPalSubmitUrl"], resp.Token));
}
}
internal static void HandleError(AbstractResponseType resp)
{
if (resp.Errors != null && resp.Errors.Length > 0)
{
// errors occured
throw new Exception(
"Exception(s) occured when calling PayPal. First exception: " +
resp.Errors[0].LongMessage);
}
}
protected Double ConvertCommaToPeriod(Double numberToConvert)
{
Double retNumber = Math.Round(-1.00, 2);
double.TryParse(Convert.ToString(Math.Round(numberToConvert, 2)),
System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.CurrentCulture, out retNumber);
return retNumber;
}
protected CurrencyCodeType ConvertToPayPalCurrencyCode(Int32 valutaId)
{
CurrencyCodeType myCurrencyCode = new CurrencyCodeType();
Valuta myValuta = Vold.FakturaManager.Bll.ValutaManager.GetItem(valutaId);
if (myValuta != null)
{
switch (myValuta.Valuta_tekst)
{
case "USD":
myCurrencyCode = CurrencyCodeType.USD;
break;
case "NOK":
myCurrencyCode = CurrencyCodeType.NOK;
break;
case "SEK":
myCurrencyCode = CurrencyCodeType.SEK;
break;
case "EUR":
myCurrencyCode = CurrencyCodeType.EUR;
break;
case "CAD":
myCurrencyCode = CurrencyCodeType.CAD;
break;
case "RUB":
myCurrencyCode = CurrencyCodeType.RUB;
break;
case "DKK":
myCurrencyCode = CurrencyCodeType.DKK;
break;
default:
myCurrencyCode = CurrencyCodeType.USD;
break;
}
}
return myCurrencyCode;
}
What remains then is to implement the ExpressCheckoutSuccess.aspx / ExpressCheckoutSuccess.aspx.cs and ExpressCheckoutCancel.aspx / ExpressCheckoutCancel.aspx.cs. The code for these two programs are attached.
For the ExpressCheckoutSuccess.aspx you basically only need the following line of code:
<asp:Button ID="btnCommitTransaction" runat="server" Text="<%$ Resources: Resource, btnExpressCheckoutCommitTransaction %>" onclick="commitTransaction_Click" />
ExpressCheckoutSuccess is called after the user has been on the PayPal page and confirmed amount, shipping address, and so on. The user is now sent back to the store's URL based on the specified return URL (remember this line of code: reqDetails.ReturnURL = url + "ExpressCheckoutSuccess.aspx";).
ExpressCheckoutSuccess.aspx will simply display a button on the page. The user will commit the transaction by pressing a button. What I do in addition is to display the shopping cart (including the shipping cost) and any tax that should be added (tax and shipping cost should be added to the total). You will see this in my program if you download it. However, there is a few things that goes on in the code behind Page_Load routine before things are displayed on the page.
In the ExpressCheckoutSuccess.aspx.cs, I query PayPal for transaction details in the Page_Load() routine. Then I calculate any sales tax and add that to the shopping cart as an item - in the same way as I added shipping cost as a shopping cart item. I then fill a label with the information regarding the transaction, such as total price, shipping cost and tax information.
In the "commitTransaction_Click" event that occurs when the user clicks the commit transaction button, I must reenter all the payment details to PayPal with updated totals, tax information, and so on. I then commit the transaction, and if no errors, the order information will be saved (in whatever way you want), and a confirmation will be shown to the customer that the transaction was successfully processed.
ExpressCheckoutCancel is very straight forward and does not need any explanation. The only thing it does is to display an error message.
Updating the Web.Config file
The only thing that now remains is to update your web.config file. Here is what you have to add:
<appSettings>
<!--
// Replace these values with your Sandbox settings. The settings here
// will not work and are provided as an example only.
// Replace PayPalUsername with your developer account user name,
// the PDTToken, APIUsername and APISignature with information
// from your Sandbox environment.
-->
<add key="PayPalUsername" value="andre@vold.no"/>
<add key="PDTToken"
value="k2ujwgulst4aUl_0iXuV27SwQZ-_egxP-pk_Vpw0gmwkH0pPGeLU4ATlSY4"/>
<add key="PayPalSubmitUrl"
value="https://www.sandbox.paypal.com/cgi-bin/webscr"/>
<add key="APIUsername" value="andre_123456789_biz_api1.vold.no"/>
<add key="APIPassword" value="123456789"/>
<add key="APISignature"
value="AC9znI2VL-a9.0E6DfeGtM5GZS0rA6-XjORu75elmiM0Od5atxuetgZx"/>
<add key="APIVersion" value="65.0"/>
<add key="com.paypal.sandbox.www.PayPalSvc"
value="https://api.sandbox.paypal.com/2.0/"/>
<!--
// This is your Production environment.
// Uncomment the settings below and comment out the Sandbox
// settings when going live.
// Replace PayPalUsername with your developer account user name,
// the PDTToken, APIUsername and APISignature.
-->
<!--
<add key="PayPalUsername" value="andre@vold.no"/>
<add key="PDTToken" value="enter your key here..."/>
<add key="PayPalSubmitUrl" value="https://www.paypal.com/cgi-bin/webscr"/>
<add key="APIUsername" value="info_api1.vold.no"/>
<add key="APIPassword" value="enter our password here..."/>
<add key="APISignature" value="enter your signature here..."/>
<add key="APIVersion" value="65.0"/>
<add key="com.paypalobjects.www.PayPalSvc"
value="https://api-3t.paypal.com/2.0/"/>
-->
</appSettings>
Hope this helps!
André Vold